Ibrahim Disouki
Ibrahim Disouki

Reputation: 2693

Read and Write to file in the same time

I want to write and read from file in the same time without errors. For example, I will starting new Thread for writing to file from my running service. In my activity i will starting new Thread for reading from the same file. I wan't to do this synchronously. Some thing like this :

  1. To wait execution of next thread until previous finished.
  2. Next thread must not start until previous thread stops, irrespective of time consumption.

My code for read and write:

public static final String ROUTE_FILE_NAME = "route.txt";

    public static void savePointToFile(Context context, String point) throws IOException {

        FileOutputStream fOut = context.openFileOutput(ROUTE_FILE_NAME, Context.MODE_APPEND);

        OutputStreamWriter osw = new OutputStreamWriter(fOut);
        osw.write(point);
        osw.flush();
        osw.close();
    }

    public static String readRouteFromFile(Context context) {
        StringBuffer fileContent = new StringBuffer(UIUtils.emptyString());
        byte[] buffer = new byte[1024];
        try {
            FileInputStream fis = context.openFileInput(ROUTE_FILE_NAME);

            int length;

            while ((length = fis.read(buffer)) != -1) {
                fileContent.append(new String(buffer));
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return fileContent.toString();
    }

Thanks in advance.

Upvotes: 2

Views: 1789

Answers (2)

Peanuts
Peanuts

Reputation: 352

You can look at a special thread pool executor service.

final ExecutorService threadpool = Executors.newSingleThreadExecutor();

Its fairly easy, just create runnables and put it in the threadpool. It contains a single thread so all your runnables are queued sequentially. Otherwise you could create a normal executorservice and set the threadpool to 1. Effectively its the same. Hope this helps

http://www.concretepage.com/java/newsinglethreadexecutor_java

So its like

WorkerThread.get(context).read() 
WorkerThread.get(context).write() 

You can even implement future calls instead of defining an explicit callback.

Just a general idea of how it can work. You need to save filepointers so you know where to pause and continue read/write. Other you will always start from the first data position in the file.

class WorkerThread {

    interface Callback {
        void onCompleteRead(String buffer, int pauseReadPointer);
        void onCompleteWrite(int pauseWritePointer);
    }

    enum Action {
        READ,
        WRITE
    }

    private static WorkerThread singleton;

    public static synchronized WorkerThread get(final Context context) {
        if (instance == null) {
            instance = new WorkerThread(context);
        }
        return instance;    
    }    



    private final Context context;

    private final ExecutorService threadPool;

    private WorkerThread(context) {
        threadPool = Executors.newSingleThreadExecutor()
    }

    // PUBLIC READ CALL
    public void read(int resumeReadPointer, Callback callback, "other params") {
        queueJob(READ, null, resumeReadPointer, callback);
    }

    // PUBLIC WRITE CALL
    public void write(String in, int resumeWritePointer, Callback callback, "other params") {
        queueJob(WRITE, in, resumeWritePointer, callback);
    }

    private void queueJob(final Action action, String buffer, final int pointer, final Callback callback) {

        /* Create handler in UI thread. */
        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {

                ResultPack pack = (ResultPack) msg.obj;
                if (Action.READ == action) {
                    callback.onCompleteRead(pack.result, pack.pointer);
                } else {
                    callback.onCompleteWrite(pack.pointer);
                }
            }
        };

        // single threadpool. everything is FIFO
        threadPool.submit(new FileRunnable(action, buffer, handler, pointer));
    }

    private class ResultPack {
        private final String result;
        private final int pointer;
        private ResultPack(String s, int p) {
            this.result = s;
            this.pointer = p;
        }
    }

    private class FileRunnable implements Runnable {

        private int pointer = 0;
        private final Handler handler;
        private final buffer = buffer;

        FileRunnable(final Action action, String buffer, final Handler handler, final int pointer) {
            this.pointer = pointer;
            this.handler = handler;
            this.buffer = buffer;
        }

        @Override
        public void run() {

            if (Action.READ == action) {
                ResultPack pack = readRouteFromFile(..., pointer);
            } else { // write
                ResultPack pack = savePointToFile(..., buffer, pointer);
            }

            Message message = Message.obtain();
            message.obj = pack;
            handler.sendMessage(message);
        }
    }
}

Upvotes: 2

BladeCoder
BladeCoder

Reputation: 12929

If you just want the read method called from a thread to wait for the write method called from another thread to be finished, and vice versa, just synchronize both methods on a common object:

private static final Object fileLock = new Object();

public static String readFile() {
    synchronize(fileLock) {
        [your current read code here]
    } 
}

public static void write(String data) {
    synchronize(fileLock) {
        [your current write code here]
    } 
}

Upvotes: 2

Related Questions