Java IO:读取仍在编写的文件

时间:2015-06-18 08:42:36

标签: java scala inputstream outputstream

我正在创建一个程序,需要从仍在编写的文件中读取。

主要问题是:如果使用在单独的线程上运行的InputStreamOutputStream类来执行读写操作,那么我将需要哪些捕获和边缘情况要注意以防止数据损坏?

如果有人想知道我是否考虑过其他非基于InputStream的方法,答案是肯定的,但我很遗憾,因为该程序仅使用库,所以在此项目中不可能适用于InputStreamOutputStream

此外,一些读者已经问过为什么这种并发症是必要的。完全写完文件后为什么不执行读取?

原因是效率。该计划将执行以下

  1. 下载一系列每个1.5MB的字节块。该程序将收到数千个这样的块,总计可达30GB。此外,同时下载块以便最大化带宽,因此可能无序到达
  2. 程序将在收到后立即发送每个块进行处理。请注意,它们将被发送以便按顺序处理。如果块m在块m-1之前到达,它们将被缓冲在磁盘上,直到块m-1到达并被发送进行处理。
  3. 执行这些块的处理,从块0开始直到块n,直到每个块都被处理完
  4. 重新发送处理结果。
  5. 如果我们要等待整个文件被转移,那么它将会对应该是一个实时系统造成很大的延迟。

3 个答案:

答案 0 :(得分:2)

使用 RandomAccessFile 。通过 getChannel 或者这样的人可以使用 ByteBuffer

您将无法“插入”或“删除”文件的中间部分。出于这样的目的,你的原始方法会很好,但是使用两个文件。

对于并发:要保持同步,您可以维护文件的单个对象模型,在那里进行更改。只有待处理的更改需要保留在内存中,其他分层数据可以根据需要重新读取和重新分析。

答案 1 :(得分:0)

你应该使用PipedInputStream和PipedOutputStream:

static Thread newCopyThread(InputStream is, OutputStream os) {
    Thread t = new Thread() {
        @Override
        public void run() {
            byte[] buffer = new byte[2048];
            try {
                while (true) {
                    int size = is.read(buffer);
                    if (size < 0) break;
                    os.write(buffer, 0, size);
                }
                is.close();
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
            }
        }
    };
    return t;
}

public void main(String[] args) throws IOException, InterruptedException {
    ByteArrayInputStream bi = new ByteArrayInputStream("abcdefg".getBytes());
    PipedInputStream is = new PipedInputStream();
    PipedOutputStream os = new PipedOutputStream(is);
    Thread p = newCopyThread(bi, os);
    Thread c = newCopyThread(is, System.out);
    p.start();
    c.start();
    p.join();
    c.join();
}

答案 2 :(得分:0)

所以你的问题(正如你现在已经清除它)是你无法开始处理直到#1块到达,你需要缓冲每个块#N(N> 1)直到你可以处理它们。

我会将每个块写入自己的文件并创建一个自定义InputStream,它将按顺序读取每个块。下载chunk文件时会命名为chunk.1.downloading,当整个块加载时,它将被重命名为chunk.1

自定义InputStream将检查文件chunk.N是否存在(其中N = 1 ... X)。如果没有,它将阻止。每次完全下载一个块时,都会通知InputStream,它将检查下载的块是否是下一个要处理的块。如果是,请按正常方式读取,否则再次阻止。