0

我正在尝试下载包含所有资源的网页。首先我下载了​​ 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;
        }
    }
4

2 回答 2

0

您的代码存在多个问题。

字符集错误

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

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

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

所以,如果你是一个网络服务器并且你想发送字符ö,你发送什么字节?

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

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

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

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

因此,这段代码被破坏了。你想要两件事之一:

选项 1 - 按原样写入数据

在执行查询网络服务器的数据并将这些信息中继到磁盘的工作时,您只想存储字节(毕竟,网络服务器提供字节,而磁盘存储字节,这很容易),但网络服务器也会发送编码,在标题中,您需要单独保存。因为要读取“字节袋”,您需要知道字符集才能将其转换为字符。

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

选项 2

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

要读取 UTF-8 文本文件,请执行以下操作:

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

这样做的原因是,该FilesAPI 与大多数其他 API 不同(与 FileReader 不同,您永远不应该使用它),默认为 UTF_8 而不是平台默认值。如果你愿意,你可以让它更具可读性:

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

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

破碎的异常处理

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

这是不行的——如果你捕捉到一个异常,要么 [A] 抛出其他东西,要么 [B] 处理问题。“记录并继续”绝对不是“处理”它。您的异常处理策略导致 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()无论“代码到这里”块如何退出,此构造都确保调用它。即使它通过异常或return语句“退出”。

问题

您的“读取文件并打印”代码除了上述三项之外大部分都很好。问题是磁盘上的 HTML 文件已损坏;错误在于您的代码从 Web 服务器读取数据并将其保存到磁盘。您没有粘贴该代码。

具体来说,System.lineSeparator()返回实际的字符串。因此,假设您粘贴的代码确实是您正在运行的代码,如果您看到实际的“10”出现,那么这意味着磁盘上的 HTML 文件在那里。这不是读取的代码。

结束的想法

更一般地说,“只需在磁盘上打印具有已知编码的文件”的工作可以用更少的代码行来完成:

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

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

于 2021-04-28T12:55:03.770 回答
0

实际上,这个函数没有问题,我在代码中使用另一个函数错误地添加了 10。

于 2021-08-24T15:20:23.250 回答