【问题标题】:BufferedReader doesn't read all lines from fileBufferedReader 不会从文件中读取所有行
【发布时间】:2017-11-18 01:51:23
【问题描述】:

我正在尝试在 Android 6 中读取 /proc/net/xt_qtaguid/stats
使用cat 命令,我得到了这个:

2 a0 0 0 123456 311 48329 737 48 1
3 b0 0 0 0 0 0 0 0
4 c0 123456 311 48329 737 48 1
5 d0 111111 111 22222 222 33 1

我的 java 代码尝试逐行读取文件:

File sysDataFile = new File(PATH_TO_FILE);
BufferedReader bufReader = null;
FileReader fileReader = null;
try {
   fileReader = new FileReader(sysDataFile);
   bufReader = new BufferedReader(fileReader);

   String line = null;
   while ((line = bufferedReader.readLine()) != null) {
       // print to console each line
       System.out.println("Line: " + line);
   }
 } catch (IOException e) {
    System.out.println("IOException thrown!");           
 } finally {
   bufReader.close();
   fileReader.close();
 }

当我运行上面的代码时,它只打印出控制台的前两行:

Line: 2 a0 0 0 123456 311 48329 737 48 1
Line: 3 b0 0 0 0 0 0 0 0

为什么?

【问题讨论】:

  • 是的,肯定是同一个文件,我想可能是第二行以一些隐藏的特殊字符结尾,阻止了代码继续阅读,但我不确定,这就是我在这里问的原因。
  • 尝试 xxd 命令以十六进制显示文件。 details here
  • @B.Bri,然后???
  • 您是否要读取/proc/ 下的文件?这些是特殊的,具有特殊权限和大小报告为 0,这可能会绊倒 Java 的读者(请参阅this question,尽管它没有很好的答案)......我没有设法重现它,即使使用旧的 Java 7 . 如果您能具体说明这是什么文件、您的内核版本和 java 版本,也许会有所帮助。

标签: java android bufferedreader filereader java-io


【解决方案1】:

由于性能不是问题,最简单和最安全的选择是在 java 的进程中启动 cat,将标准输出重定向到流并读取阅读器中的内容。以此为指导:Run cat command in Android

无需修改权限即可提供反引号

【讨论】:

    【解决方案2】:

    我正在尝试在 Android 6 中读取 /proc/net/xt_qtaguid/stats

    在 Linux 中,/proc/ 下的文件实际上并不是文件:它们由 procfs 处理,这是一个特殊的文件系统,每次读取或写入文件条目时都会执行代码(代码是内核模块中定义的回调函数)。所以这些伪文件不像普通文件那样是静态的,而是完全动态。大小给出了一个有趣的线索:(大多数)这些文件的长度为 0(可以通过 ls -l 看到),但在读取时它们会显示一些内容。

    简而言之,从 2 个不同的上下文读取同一个文件会产生 2 个不同的结果。

    在这种情况下,“文件”回调由 xt_qtaguid module for Android 处理,它管理“每个应用程序/委托的数据使用监控”。

    This answer 说:

    这个虚拟文件的read_proc函数限制了uid,每个应用程序只能读取头部和自己的行。

    第一部分有点含糊,但似乎表明差异是基于用户 ID,当常规应用程序读取此文件时,模块只会“打印”2行数据(请注意Android assigns a unique user ID to each application and runs it as that user in a separate process)。

    您没有提供足够的详细信息,但我必须假设当您使用 cat 从 adb 打印它时,您可能没有与尝试从应用程序读取它时相同的用户 ID 和权限。我没有跟踪确切的实现细节(如果你愿意,the source for this module can be read here),但其他变量可能会发挥作用。

    The doc says:

    对于将网络数据传输作为服务提供的应用程序,例如下载管理器、媒体流服务等,可以使用TrafficStats.setThreadStatsUid() 函数调用。调用者必须拥有android.permission.MODIFY_NETWORK_ACCOUNTING 权限才能重新分配网络流量的所有权。

    因此进程/应用程序可以使用TrafficStats.setThreadStatsUid() 来从该文件中获取更多行,但这需要MODIFY_NETWORK_ACCOUNTING 权限。

    【讨论】:

    • 1.文件大小无关紧要。 2、cat可以在adb里面跑,也可以在adb外面跑,userID不一样没道理。 3.cat能做到的,Java都能做到。最终两者都致电read()。内核在内部做什么取决于内核。不管是cat还是java调用read()
    • 文件大小并不能解释差异,但我认为表明文件的特殊性非常相关,可能不清楚,所以我编辑了。我还使其余部分变得更加模糊,因为我对该特定文件的细节没有明确的答案。 OP 问题的第一行最初并不存在,之前它不太清楚。我问他们是否正在阅读/proc,当我确认了这一点后,我认为关于 procfs 的解释会很有用。
    • @EJP 另外,我认为在 Android 中,each app runs with its own user id,这样可以解释不同的用户 ID。 "Android 系统为每个 Android 应用程序分配一个唯一的用户 ID (UID),并在单独的进程中以该用户身份运行它。"
    【解决方案3】:

    readLine() 方法一直读取到下一个 '\n' 字符。假设,如果你有两个连续的 '\n' 字符,那么 readLine() 可能 过早地返回 null。但是,如果是这种情况,那么 cat 应该在这两行之间多加一行。

    此时你可以尝试两件事:

    1. 检查系统文件和程序使用的字符集是否相同
    2. 改变这个:

      String line = null;
      while ((line = bufferedReader.readLine()) != null) {
          // print to console each line
          System.out.println("Line: " + line);
      }
      

      到这里:

      char c = null;
      while ((c = (char)bufferedReader.read()) != null) {
          // print to console each char
          System.out.println("Line: " + c);
      }
      

    看看会发生什么。

    【讨论】:

    • 没关系,skadya 在您的原始评论线程中链接到的问题可能只是您的问题。
    • readLine() 一直读取到下一行终止符。其中两个连续将产生一个空行。 ""。不是过早的空值。 BufferedReader.read() 返回int,它不能为空,char 也不能。答案没有意义,代码无法编译。
    • 但是换行符 ('\n') 不是行终止符吗?我其实很好奇。
    • 是的,\r\n 也是如此,\r 本身也是如此。请参阅 Javadoc。
    猜你喜欢
    • 2017-03-20
    • 2013-03-23
    • 2018-06-16
    • 2015-05-12
    • 1970-01-01
    • 1970-01-01
    • 2021-12-21
    • 1970-01-01
    • 2017-08-12
    相关资源
    最近更新 更多