Java IO 字节流计数问题

[code="java"]
long count = 0;
String line = br.readLine();
while (line != null) {
if (count > length) {
break;
}

                count += line.getBytes("UTF-8").length;
                count += 1; // Add \r's length
                System.out.println(Thread.currentThread() + "  " + line);
                System.out.println(" count:" + count);
                line = br.readLine();
            }

[/code]

用这样的方法来统计已读的字节数为什么输出的结果不对呢?具体的说count统计的数目比实际的要少,这是什么原因造成的?

io

7个回答

[code="java"]File file = new File("D:\todo.txt");
BufferedReader br = new BufferedReader(new FileReader(file));
long length = 1261192704;
long count = 0;
String line = br.readLine();
while (line != null) {
if (count > length) {
break;
}
count += 2;
count += line.getBytes("utf-8").length;
System.out.println(line);
line = br.readLine();
}

    System.out.println(count);
    FileInputStream fis = new FileInputStream(file);
    System.out.println(fis.available());[/code]

测试结果:
1、如果windows上边读windows文件 返回结果是正确的;
2、如果windows上边读linux文件结果是有偏差的(count += 1)。

[quote]getBytes
public byte[] getBytes(Charset charset)使用给定的 charset 将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。
此方法总是使用此字符集的默认替代 byte 数组替代错误输入和不可映射字符序列。如果需要对编码过程进行更多控制,则应该使用 CharsetEncoder 类。
[/quote]

难道有些linux字符在windows上无法映射? 你试下 在linux上读取linux文件 结果对吗

iteye_19215
iteye_19215 嗯,有道理,谢谢~我自己在去linux环境下测试一下
接近 8 年之前 回复
jinnianshilongnian
jinnianshilongnian 三种方式: 1、BufferedReader 2、FileInputStream fis = new FileInputStream(file);System.out.println(fis.available()); 3、while(fis.read() != -1) {c++;}
接近 8 年之前 回复
jinnianshilongnian
jinnianshilongnian while (line != null) { count += lineLength; count += line.getBytes("utf-8").length; line = br.readLine(); } 这种方式唯一可能多读一个换行,即多加1个换行符长度(如果最后一行没有换行)
接近 8 年之前 回复
iteye_19215
iteye_19215 你是用的二进制流来读取的吗?我这里用的是reader,而且是按行来读取的
接近 8 年之前 回复
jinnianshilongnian
jinnianshilongnian 我分别在linux和window上又试了下,你的方式没有问题:(怀疑是不是你那边linux操作系统不是utf-8的?) 我测试的代码: File file = new File("D:\\javass-access.log"); BufferedReader br = new BufferedReader(new FileReader(file), 1); long count = 0; int lineLength = 1; String line = br.readLine(); while (line != null) { count += lineLength; count += line.getBytes("utf-8").length; line = br.readLine(); } System.out.println(count); FileInputStream fis = new FileInputStream(file); System.out.println(fis.available()); long c = 0; while(fis.read() != -1) { c++; } System.out.println(c);
接近 8 年之前 回复
jinnianshilongnian
jinnianshilongnian 我试了下 一样的结果 [code]long c = 0; while(fis.read() != -1) { c++; }[/code] 这个是可以获取到正确的结果的
接近 8 年之前 回复
iteye_19215
iteye_19215 感谢!我这里没有测试环境
接近 8 年之前 回复
jinnianshilongnian
jinnianshilongnian 我到linux上试试
接近 8 年之前 回复
iteye_19215
iteye_19215 莫非是存在幽灵字符?我觉得这个有可能
接近 8 年之前 回复

要考虑 换行符 在window上边 是\r\n(两个字节) 在linux上是\r(一个);

jinnianshilongnian
jinnianshilongnian 我也在本地试呢,确实有偏差 研究下 咋回事
接近 8 年之前 回复
iteye_19215
iteye_19215 哥。。你别呵呵啊,我想真的不是因为换行符的问题,我读取的文件片段有8M,60000多行,如果是因为换行符怕是偏差不止这几十KB啊
接近 8 年之前 回复
jinnianshilongnian
jinnianshilongnian 哦 这个 呵呵
接近 8 年之前 回复
iteye_19215
iteye_19215 这个。。我也不知道,我的日志是从linux上down下来的,而且我做的测试告诉我count+=2误差偏移相当大
接近 8 年之前 回复
jinnianshilongnian
jinnianshilongnian 在windows上换行符是\r\n,所以是两个字节 count+=2 为什么不对呢?
接近 8 年之前 回复
iteye_19215
iteye_19215 InputStream in = new FileInputStream(file); in.skip(start); 跳过之后读取的那行之前的线程已经读取过了
接近 8 年之前 回复
iteye_19215
iteye_19215 count+2不对,因为我的业务场景是分段读取大文件,所以我要skip一定量的字节数,但是一个线程读取结束的位置和skip过的位置不符,数量差在50KB左右,所以知道不对
接近 8 年之前 回复
jinnianshilongnian
jinnianshilongnian 你怎么知道误差在50kb左右 怎么对比的
接近 8 年之前 回复
jinnianshilongnian
jinnianshilongnian 如果是windows的话 count+=2
接近 8 年之前 回复
iteye_19215
iteye_19215 我现在就只是单纯的在windows下测试,读取60000多行数据的误差大概在50KB左右,我不解这个误差是哪里来的,应该不是换行符,count += 1这里就是针对换行符做的处理
接近 8 年之前 回复

count += 1; // Add \r's length 这个不用要了吧,已经作了line != null的判断了 应该会排除掉空的回车。每次读一行就用count += 1;好像是错误的。

iteye_19215
iteye_19215 +1这是在计算换行符占用的位置
接近 8 年之前 回复

if (count > length) {

break;

}

这个判断感觉也好别扭。不知道是什么 可能也会影响结果 都非空判断了 不用break了吧 count>length是判断什么的?

iteye_19215
iteye_19215 忘记去掉了,那个是业务相关的,可以忽略
接近 8 年之前 回复

问题找到了,
Reader 在读取字符时,在linux上你是把换行符当作一个字节看待,但是如果我忘文件里写了\r\n 你也是看作一个的(就是说linux上也可能写\r\n 可是你只记录了1个字节),所以出问题了。
[code="java"]
FileInputStream fis = new FileInputStream(file);
System.out.println(fis.available());

    long r = 0;
    long n = 0;
    long c = 0;
    int i = fis.read(); 
    while(i != -1) {
        if(i == '\r') {
            r++;
        }
        if(i == '\n') {
            n++;
        }

        c++;
        i = fis.read();
    }
    System.out.println(c);
    System.out.println(r);
    System.out.println(n);

[/code]

:oops: 第二行的 String line = br.readLine(); 经读了一些字符了,但是此时count = 0。。。所以你的程序应该少了第二行程序读到的字符数。

按照byte流读取..不要按照read流读取

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐