如何在Java中的两个不同位置访问同一文件

时间:2011-07-31 23:55:30

标签: java sorting

我想同时从两个不同的地方读取文件。我还想使用缓冲的i / o流来提高效率。我尝试在我自己给定的Java API上运行,但它不起作用。有人会帮忙吗?我需要它进行外部合并排序。谢谢你的帮助!

2 个答案:

答案 0 :(得分:1)

你需要创建一个RandomAccessFile,它基本上是Java的C内存映射文件。

found an example

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) {
}

编辑,你声明你不能使用RandomAccessFile,这是跳过文件的唯一方法。如果你没有它,那么你必须按顺序读取文件,但这并不意味着你不能打开多个指向同一文件的指针进行阅读。

我将以下测试/样本放在一起,它清楚地表明您可以使用不同的读指针“两次”打开文件,并顺序地将文件的两半相加。同样,如果您需要随机访问,您必须使用RandomAccessFile,这就是我建议的内容,但是请您继续:

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;
        }

    }

}

答案 1 :(得分:0)

什么阻止你只是打开文件两次,并使用它就好像它是两个独立的文件?

        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();
    }