Java 跨不同操作系统读取新行字符

Java 跨不同操作系统读取新行字符,java,vim,file-io,Java,Vim,File Io,我遇到了这样一种情况:我正在读取某个日志文件,然后通过下面的代码段计算遇到的行数 byte[] c = new byte[1024]; long count = 0; int readChars = 0; while ((readChars = is.read(c)) != -1) { for (int i = 0; i < readChars; ++i) { if (c[i] == '\n') { ++count; }

我遇到了这样一种情况:我正在读取某个日志文件,然后通过下面的代码段计算遇到的行数

byte[] c = new byte[1024];
long count = 0;
int readChars = 0;
while ((readChars = is.read(c)) != -1) {
    for (int i = 0; i < readChars; ++i) {
        if (c[i] == '\n') {
            ++count;
        }
    }
}
byte[]c=新字节[1024];
长计数=0;
int readChars=0;
而((readChars=is.read(c))!=-1){
for(int i=0;i
我的问题是,当我尝试读取一个文件(CSV、Syslog或任何其他野生格式)时,它运行正常,并给出正确的结果。但是,当我试图运行一个通过mac生成的文件时,它会断线并简单地报告读取了一行

现在我的日志文件很大,我知道它有几千行日志,但它只读取一行。我在Sublime中打开了这个文件,可以看到所有单独的行,但是当我通过VIM查看这个文件时,它只显示了一个文件,每行末尾都有一个字符“^M”(我猜它正在使用它作为行终止符)

下面是两行的示例。您可以看到,vim正在显示^M字符,它应该是一个新行

15122,25Dec2013,19:42:25192.168.5.1,日志,允许,eth0,出站,应用程序控制,网络,Bob(+),Bob(+),Bob(+),59857d77,************,其他:Wget/1.13.4(linux gnu),其他:服务器,192.168.5.760461741:1,,,,,,,,******,,***,,,,,^M359,23Dec2013,18:54:03192.5.1,日志,允许,eth0,出站,应用程序控制,网络,Charlie(+)),,,c0fa2dac,其他:服务器,192.168.5.660340847:1,,,,,,,,*********,,***,,,^M


关于如何解决这个问题有什么建议吗

在换行之前的第一个问题是,您正在读取字节,然后将其视为字符。您实际上假设ISO-8859-1的编码可能不正确。您应该改用
InputStreamReader

还有一个问题是操作系统有不同的换行符。。。使用
BufferedReader.readLine()
以处理
\n
\r
\r\n
的换行符的方式读取行

因此,您的代码将变成:

int count = 0;
try (BufferedReader reader = new BufferedReader(
     new InputStreamReader(is, charset))) {
   while (reader.readLine() != null) {
       count++;
   }
}

即使在换行之前,第一个问题是,您正在读取字节,然后将其视为字符。您实际上假设ISO-8859-1的编码可能不正确。您应该改用
InputStreamReader

还有一个问题是操作系统有不同的换行符。。。使用
BufferedReader.readLine()
以处理
\n
\r
\r\n
的换行符的方式读取行

因此,您的代码将变成:

int count = 0;
try (BufferedReader reader = new BufferedReader(
     new InputStreamReader(is, charset))) {
   while (reader.readLine() != null) {
       count++;
   }
}
换行符(
^J
,0x0a)和回车符(
^M
,0x0d)都用作换行符;Unix使用第一种(旧的)Mac,后者使用Windows两者的组合(CR-LF)

如果您没有一个文件输入库来抽象它(如果您必须支持旧的Mac格式(作为新的MacOS,因为内核基于Unix,也使用LF)),请将LF和CR都视为行分隔符,并且不要将Windows使用的CR-LF计算两次

维姆 Vim检测的内容由
'fileformats'
选项决定。你也可以通过

:set fileformats+=mac
换行符(
^J
,0x0a)和回车符(
^M
,0x0d)都用作换行符;Unix使用第一种(旧的)Mac,后者使用Windows两者的组合(CR-LF)

如果您没有一个文件输入库来抽象它(如果您必须支持旧的Mac格式(作为新的MacOS,因为内核基于Unix,也使用LF)),请将LF和CR都视为行分隔符,并且不要将Windows使用的CR-LF计算两次

维姆 Vim检测的内容由
'fileformats'
选项决定。你也可以通过

:set fileformats+=mac

谢谢你的回复。但是您是否同意
reader.readLine()
在这里不是开销操作,因为我唯一的要求是计算日志文件中的行数?我执行了一些微基准测试,结果表明,当使用
reader.readLine()
方法时,有相当多的GC调用。感谢您的回复。但是您是否同意
reader.readLine()
在这里不是开销操作,因为我唯一的要求是计算日志文件中的行数?我执行了一些微基准测试,结果表明,在使用
reader.readLine()
方法时,有相当多的GC调用。
将LF和CR都视为行分隔符,不要将Windows使用的CR-LF计算两次。
您能详细说明一下吗?@SaifAsif:,不要简单地把LF算作一,把CR算作一,因为在Windows上会有两个(而不是一个)。基本上,先检查
,我明白了。是的,这很有道理。过一会儿我会试试看是否有用。再次感谢,谢谢!解决了我的问题!我的问题是我在windows上计算了两次。
将LF和CR都视为行分隔符,不要将windows使用的CR-LF计算两次。
您能不能