我有一个大文件,我只需删除多行 有没有办法在不打开新文件的情况下执行此操作并复制整个文本?
编辑: 主要问题是当它运行在多个带有大txt filse的线程中时程序失败
答案 0 :(得分:3)
有没有办法在不打开新文件的情况下执行此操作并复制整个文本?
不,没有。当然,如果你想安全地安装,也没有。
RandomAccessFile
也不会对你有所帮助。它允许您用相同数量的字节替换文件中的字节序列,但这并不等于删除一行。
您可以使用这样的RAF:
给定初始状态
L1L2L3...LN
将L2L3...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。