从文本文件java中删除一行

时间:2014-10-05 11:44:20

标签: java string

我有一个大文件,我只需删除多行 有没有办法在不打开新文件的情况下执行此操作并复制整个文本?

编辑: 主要问题是当它运行在多个带有大txt filse的线程中时程序失败

3 个答案:

答案 0 :(得分:3)

  

有没有办法在不打开新文件的情况下执行此操作并复制整个文本?

不,没有。当然,如果你想安全地安装,也没有。

RandomAccessFile也不会对你有所帮助。它允许您用相同数量的字节替换文件中的字节序列,但这并不等于删除一行。

您可以使用这样的RAF:

  

给定初始状态L1L2L3...LNL2L3...LN替换为L3...LN

或者您可以使用RAF来滑动"根据@ halfbit的回答一次一行。

然而:

  • 在最坏的情况下,您正在复制整个文件内容,而一般情况涉及读取和写入O(N)行的字节。

  • 这样做的简单方法是在内存中保留O(N)行。

  • "滑动"方法需要O(N) I / O操作(即系统调用)。

  • 最重要的是:通过就地文件更新删除行是有风险的。如果应用程序在进程中间中断(例如电源故障),那么最终会出现损坏的文件。

FWIW:这不是Java 本身的限制。相反,它限制了现代操作系统表示/建模文件的方式。

答案 1 :(得分:0)

查看Random Access Files,以便将文件指针放在所需位置并移动文字。

答案 2 :(得分:0)

以下是一些独立的示例代码,使用RandomAccessFile删除行而不用打开新文件,这似乎对我有用。 (虽然需要就地复制。)

public static void main(String[] args) {
    try {
        // prepare test file
        String path = "/tmp/test.txt";
        writeTestLines(path, 999999);

        // mode "rws": read + write synchronous
        RandomAccessFile raf = new RandomAccessFile(path, "rws");

        int bufSize = 1 << 20; // 1 MiB
        Scanner s = new Scanner(new BufferedInputStream(new FileInputStream(raf.getFD()), bufSize));
        PrintWriter pw = new PrintWriter(new BufferedOutputStream(new FileOutputStream(raf.getFD()), bufSize));
        long writeOffset = 0;
        for (int nr = 1;; nr++) {
            if (!s.hasNextLine())
                break;
            String line = s.nextLine();
            if (nr != 2 && !line.contains("00")) {
                // switch to writing: save read offset, seek write offset
                long readOffset = raf.getFilePointer();
                raf.seek(writeOffset);
                pw.println(line);
                // switch to reading: save write offset, seek read offset
                writeOffset = raf.getFilePointer();
                raf.seek(readOffset);
            }
        }

        // write buffered output and truncate file
        raf.seek(writeOffset);
        pw.flush();
        raf.setLength(raf.getFilePointer());

        pw.close();
        s.close();
        raf.close();
    } catch (Exception ex) {
        ex.printStackTrace(System.err);
    }
}

public static void writeTestLines(String path, int n) throws IOException {
    PrintWriter pw = new PrintWriter(path);
    for (int i = 1; i <= n; i++) pw.println("line " + i);
    pw.close();
}

请注意,此代码假定扫描程序读取的行结尾与PrintWriter生成的行结尾相同(例如,不仅仅是Windows上的单个LineFeed)。

请注意,上述代码可以优化为不重写任何未更改的文件头 - 例如首先跟踪写入偏移,然后切换到“普通”PrintWriter。