开发者

How to access the same file in two different places in Java

I want to read from file from two different places concurrently. I also want to use 开发者_如何学Gobuffered i/o stream for efficiency. I tried to work out sth on my own given java API, but it's not working. Anybody will help? I need it for external merge-sort. Thanks for help!


You need to create a RandomAccessFile, which is basically Java's equivalent of C's memory mapped file.

I found an example of this:

try {
    File file = new File("filename");

    // Create a read-only memory-mapped file
    FileChannel roChannel = new RandomAccessFile(file, "r").getChannel();
    ByteBuffer roBuf = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, (int)roChannel.size());

    // Create a read-write memory-mapped file
    FileChannel rwChannel = new RandomAccessFile(file, "rw").getChannel();
    ByteBuffer wrBuf = rwChannel.map(FileChannel.MapMode.READ_WRITE, 0, (int)rwChannel.size());

    // Create a private (copy-on-write) memory-mapped file.
    // Any write to this channel results in a private copy of the data.
    FileChannel pvChannel = new RandomAccessFile(file, "rw").getChannel();
    ByteBuffer pvBuf = roChannel.map(FileChannel.MapMode.READ_WRITE, 0, (int)rwChannel.size());
} catch (IOException e) {
}

Edit, you stated you can't use a RandomAccessFile, which is the only way to skip up and down through the file. If you're stuck without it, then you must read the file sequentially, but that doesn't mean that you can't open multiple pointers to the same file for reading.

I put together the following test/sample and it shows clearly that you can open the file "twice" with different read pointers and sequentially sum two halves of the file. Again, if you need random access, you must use a RandomAccessFile, and that's what I'd suggest, but here you go:

public class FileTest {

    public static void main(String[] args) throws IOException, InterruptedException, ExecutionException{

        File temp = File.createTempFile("asfd", "");
        BufferedWriter wrt = new BufferedWriter(new FileWriter(temp));

        int testLength = 10000;
        int numWidth = String.valueOf(testLength).length();

        int targetSum = 0;
        for(int i = 0; i < testLength; i++){
            // each line guaranteed to have a good number of characters for our test
            wrt.write(String.format("%0"+ numWidth +"d\n", i));
            targetSum += i;
        }
        wrt.close();

        BufferedReader rdr1 = new BufferedReader(new FileReader(temp));
        BufferedReader rdr2 = new BufferedReader(new FileReader(temp));

        rdr2.skip((numWidth+1)*testLength / 2); // skip first half of the lines

        Summer sum1 = new Summer(rdr1, testLength / 2);
        Summer sum2 = new Summer(rdr2, testLength / 2);

        ExecutorService executor = Executors.newFixedThreadPool(2);
        Future<Integer> halfSum1 = executor.submit(sum1);
        Future<Integer> halfSum2 = executor.submit(sum2);

        System.out.println("Total sum = " + (halfSum1.get() + halfSum2.get()) + " reference " + targetSum);

        rdr1.close();
        rdr2.close();

        temp.delete();
    }

    private static class Summer implements Callable<Integer>{
        private BufferedReader rdr;
        private int limit;

        public Summer(BufferedReader rdr, int limit) throws IOException{
            this.rdr = rdr;
            this.limit = limit;
        }

        @Override
        public Integer call() throws Exception {
            System.out.println(Thread.currentThread().getName() + " started " + System.currentTimeMillis());
            int sum = 0;
            for(int i = 0; i < limit; i++){
                sum += Integer.valueOf(rdr.readLine());
                // uncomment to see interleaving of threads:
                //System.out.println(Thread.currentThread().getName());
            }
            System.out.println(Thread.currentThread().getName() + " finished " + System.currentTimeMillis());
            return sum;
        }

    }

}


What's to stop you from simply opening the file twice, and working with it as if it were two independent files?

        File inputFile = new File("src/SameFileTwice.java");
    BufferedReader in1 = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile)));
    BufferedReader in2 = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile)));
    try {
        String strLine;
        while ((strLine = in1.readLine()) != null && (strLine = in2.readLine()) != null) {
            System.out.println(strLine);
        }
    } finally {
        in1.close();
        in2.close();
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜