使用 LF 的十六进制代码将缓冲区转换为字符串时出现问题

Issue when convert buffer to string with hexadecimal code of LF

我正在尝试下载网页及其所有资源。首先我下载了​​html,但是什么时候一定要保持文件格式,使用下面这个功能。 有一个问题,我在最终文件中发现了 10 个,当我发现 LF 或行转义的十六进制代码时。这给我的 javascript 功能带来了麻烦。

最终结果示例:

<!DOCTYPE html>10<html lang="fr">10 <head>10    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />10  

有人可以帮我找到真正的问题吗?

public static String  scanfile(File file) {
        StringBuilder sb = new StringBuilder();
        try {
            BufferedReader bufferedReader = new BufferedReader(new FileReader(file));

            while (true) {
                String readLine = bufferedReader.readLine();
                if (readLine != null) {
                    sb.append(readLine);
                    sb.append(System.lineSeparator());
                    Log.i(TAG,sb.toString());
                } else {
                    bufferedReader.close();
                    return sb.toString();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

您的代码存在多个问题。

字符集错误

BufferedReader bufferedReader = new BufferedReader(new FileReader(file));

这不会以棘手的方式起作用。

文件(以及网络服务器提供给您的数据)以字节为单位。数字流,每个数字都在 0 到 255 之间。

那么,如果您是网络服务器并且您想要发送字符 ö,您发送什么字节?

答案很复杂。解释某些字符如何以字节形式呈现的映射称为 字符集编码 (缩写为 'charset')。

任何时候将字节转换为字符,反之亦然,总是涉及一个字符集。总是。

因此,您正在读取一个文件(字节),并将其转换为 Reader(字符)。因此,涉及到字符集。

哪个字符集? new FileReader(path) 的 API 解释了哪一个:“系统默认值”。 你不想要那个

因此,这段代码被破解了。您想要以下两件事之一:

选项 1 - 按原样写入数据

在执行查询网络服务器数据并将此信息中继到磁盘的工作时,您只想存储字节(毕竟,网络服务器提供字节,而磁盘存储字节,这很容易),但是网络服务器 在 header 中发送编码,您需要单独保存它。因为要那个'sack of bytes',你需要知道字符集才能把它变成字符。

你会怎么做?好吧,由你决定。例如,您可以规定数据文件以字符集编码的名称开头(通过 header 发送),然后是 0 字节,然后是未修改的数据。我认为您应该选择选项 2,但是

选项 2

text-based 文档(HTML 是)的另一个更好的选择是:读取数据时,使用 header 告诉的编码将其转换为字符你。然后,为了将其保存到磁盘,使用 UTF-8 将字符转换回字节,这是一种很好的编码和行业标准。这样,在阅读时,您只知道它是 UTF-8,句点。

要读取 UTF-8 文本文件,您需要:

Files.newBufferedReader(Paths.get(file));

之所以可行,是因为 Files API 与大多数其他 API 不同(并且与文件 Reader 不同,您 永远不要使用 ),默认为 UTF_8 而不是 platform-default。如果你愿意,你可以让它更具可读性:

Files.newBufferedReader(Paths.get(file), StandardCharsets.UTF_8);

同样的事情 - 但现在在代码中很清楚发生了什么。

损坏的异常处理

} catch (IOException e) {
  e.printStackTrace();
  return null;
}

这不行 - 如果您捕获到异常,要么 [A] 抛出其他东西,要么 [B] 处理问题。而'log it and keep going'绝对不是'handling'而已。您的异常处理策略导致 1 个错误,导致一千个堆栈跟踪出现一千个错误,除了第一个之外,所有这些都是不受欢迎的和不相关的,因此为什么这是可怕的代码,您永远不应该这样写。

简单的解决方案是将 throws IOException 放在 scanFile 方法上。该方法本质上与文件交互,它应该抛出它。请注意,您的 psv main(String[] args) 方法可以而且通常应该声明为 throws Exception.

它还使您的代码更简单、更短,耶!

资源管理失败

文件阅读器是一种资源。你必须关闭它,不管发生什么。您没有这样做:如果 .readLine() 抛出异常,那么您的代码将跳转到 catch 处理程序并且永远不会执行 bufferedReader.close

解决方案是使用 ARM(自动资源管理)构造:

try (var br = Files.newBufferedReader(Paths.get(file), StandardCharsets.UTF_8)) {
    // code goes here
}

此构造确保调用 close(),无论 'code goes here' 块如何退出。即使它 'exits' 通过异常或 return 语句。

问题

您的 'read a file and print it' 代码除上述三项外大部分都没有问题。问题是磁盘上的 HTML 文件已损坏;错误在于您的代码从网络服务器读取数据并将其保存到磁盘。您没有粘贴该代码。

具体来说,System.lineSeparator() returns 实际字符串。因此,假设您粘贴的代码确实是您 运行 的代码,如果您看到实际的“10”出现,则意味着磁盘上的 HTML 文件中有它。不是读码。

结束语

更一般地说,'just print a file on disk with a known encoding' 的工作可以用更少的代码行来完成:

public static String scanFile(String path) throws IOException {
    return Files.readString(Paths.get(path));
}

您应该改用上面的代码。简单,简短,没有任何错误,不会泄漏资源,有适当的异常处理,并将使用UTF-8。

其实这个函数没有问题我是在我的代码中使用另一个函数错误地加了10。