Java 正在读取尚未读取的文件内容';未完成复制/上传

Java 正在读取尚未读取的文件内容';未完成复制/上传,java,file,concurrency,Java,File,Concurrency,例如,服务器每5秒钟检查一次文件是否已添加到特定目录。如果是,则读取并处理它们。相关文件可能相当大(例如100+个月),因此复制/上传到上述目录可能相当长 如果服务器试图访问尚未完成复制/上载的文件,该怎么办?JAVA如何管理这些并发访问?它是否取决于服务器的操作系统 我做了一次尝试,从远程服务器复制一个1300000行的TXT文件(即大约200个Mo)到我的本地计算机:大约需要5秒钟。在此期间,我运行以下JAVA类: publicstaticvoidmain(字符串[]args)引发异常{

例如,服务器每5秒钟检查一次文件是否已添加到特定目录。如果是,则读取并处理它们。相关文件可能相当大(例如100+个月),因此复制/上传到上述目录可能相当长

如果服务器试图访问尚未完成复制/上载的文件,该怎么办?JAVA如何管理这些并发访问?它是否取决于服务器的操作系统


我做了一次尝试,从远程服务器复制一个1300000行的TXT文件(即大约200个Mo)到我的本地计算机:大约需要5秒钟。在此期间,我运行以下JAVA类:

publicstaticvoidmain(字符串[]args)引发异常{
String local=“C:\\large.txt”;
BufferedReader reader=新的BufferedReader(新文件读取器(本地));
int行=0;
while(reader.readLine()!=null)
行++;
reader.close();
系统输出打印项次(行+行);
}
我得到以下例外情况:

线程“main”java.lang.OutOfMemoryError中的异常:java堆空间 位于java.util.Arrays.copyOf(Arrays.java:2882) 位于java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:100) 位于java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:515) 在java.lang.StringBuffer.append处(StringBuffer.java:306) 位于java.io.BufferedReader.readLine(BufferedReader.java:345) 位于java.io.BufferedReader.readLine(BufferedReader.java:362) main.main.main(main.java:15)
在复制完文件后运行该类时,我会得到预期的输出(即
1229761行
),因此异常不是由于文件的大小造成的(正如我们一开始所想)。JAVA在后台做了什么,抛出了这个
OutOfMemoryError
异常?

为什么要使用缓冲读取器来计算行数

从javadoc: 从字符输入流读取文本,缓冲字符,以便高效读取字符、数组和行

这意味着它将“缓冲”,即保存在内存中导致堆栈转储的整个文件。试试文件阅读器

JAVA如何管理这些并发访问?它是否取决于服务器的操作系统

这取决于具体的操作系统。如果您在单个JVM类中运行一个副本和服务器,可能会有很大帮助。然而,如果客户机和服务器由不同的JVM表示(或者更多JVM是在不同的机器上启动的),那么这一切都是特定于平台的

与FileChannel一样,此类实例提供的文件视图保证与同一程序中其他实例提供的同一文件的其他视图一致。但是,由于底层操作系统执行的缓存和网络文件系统协议引起的延迟,此类实例提供的视图可能与其他并发运行程序看到的视图一致,也可能不一致。这是真实的,不管这些其他程序是用什么语言编写的,也不管它们是在同一台机器上运行还是在其他机器上运行。任何此类不一致的确切性质取决于系统,因此未明确说明


您是否尝试过使用大量的Xmx来确保它不是真正的OOME?我的猜测是readLine()在某种程度上实际上没有找到换行符(可能是因为换行符因某种原因、不同的O.S.或某些编码问题而不同)并立即读取一个非常大的行。@assylias我尝试将JAVA堆大小设置为最大1GB(即
-Xmx1024m
),但仍然会引发异常。@Pescis我也想过,但正如我所解释的,在复制完文件后运行该类时,我会得到预期的输出(即
1229761行
),这意味着新行字符不是问题的症结所在。避免此问题的正常方法是将文件复制到临时文件名,服务器进程将忽略该文件,然后在复制完成后,将文件重命名为服务器期望的文件名。这样,服务器进程就不会看到不完整的文件。您可以更改复制过程以执行此操作吗?如果不是,另一种方法是检查文件大小,只有在文件大小在过去5秒内没有增加时才处理文件。问题不是读取行,而是访问这样的文件。我只是举了一个例子来说明我的问题。我的答案实际上仍然是正确的。你想知道为什么你会得到一个OOME,这是因为你试图把一个巨大的文件放在内存中。这就给你留下了两个选择:1。不要把它放在内存中(正如我上面建议的),或者2。按照其他人的建议,通过-Xmx标志增加内存量。