0

现在,我有一些代码可以读取页面并将所有内容保存到 html 文件中。但是,有一些问题......一些标点符号和特殊字符显示为问号。

当然,如果我手动执行此操作,我会使用 Unicode 编码而不是默认的 ANSI 保存 .txt 文件。我环顾四周,我所看到的只是抱怨Java不可能或我不理解的一半解释......

无论如何,谁能帮我纠正问号?这是我下载页面的代码部分。(lister 创建了一个 url 数组来下载,用于有页面的站点。你可以忽略它,它工作正常。)

public void URLDownloader(String site, int startPage, int endPage) throws Exception {
String[] pages = URLLister(site, startPage, endPage);
String webPage = pages[0];
int fileNumber = startPage;
if (startPage == 0)
  fileNumber++;

//change pages
for(int i = 0; i < pages.length; i++) {
  webPage = pages[i]; 
  URL url= new URL(webPage);
  BufferedReader in = new BufferedReader( 
                                         new InputStreamReader(url.openStream()));
  PrintWriter out = new PrintWriter(name + (fileNumber+i) + ".html");
  String inputLine;


  //while stuff to read on current page
  while ((inputLine = in.readLine()) != null) {
    out.println(inputLine); //write line of text
  }
  out.close();    //end writing text
  if (startPage == 0)
    startPage++;
  console.append("Finished page " + startPage + "\n");
  startPage++;
}      
4

1 回答 1

2

如果我手动执行此操作,我将使用 Unicode 编码而不是默认的 ANSI 保存 .txt 文件

Windows 在这里给你误导性的术语。没有像“Unicode”这样的编码;Unicode 是以不同方式编码成字节的字符集。Windows 称为“Unicode”的编码实际上是 UTF-16LE。这是一个每个代码单元两个字节的编码,不兼容 ASCII,通常不方便;网页往往不能很好地使用它。

(对于 'ANSI' 代码页的价值,它也与 ANSI 无关。另外还有变化......)

PrintWriter out = new PrintWriter(name + (fileNumber+i) + ".html");

这将使用 Java 默认编码创建一个文件,在您的情况下这可能是 ANSI 代码页。要指定不同的编码,请使用可选的第二个参数PrintWriter

PrintWriter out = new PrintWriter(name + (fileNumber+i) + ".html", "utf-8");

UTF-8 通常是一个不错的选择:作为 UTF,它可以存储所有 Unicode 字符,并且它也兼容 ASCII。

然而!您还使用默认编码读取字符串:

BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));

这可能不是页面的编码。同样,您可以使用可选参数指定编码:

BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));

如果网页实际上是作为 UTF-8 提供的,这将正常工作。

但如果不是呢?实际上有多种方法可以确定 HTML 页面的编码:

  1. Content-Type: text/html;charset=...标头参数(如果存在)。
  2. <?xml声明中,如果它被用作application/xhtml+xml.
  3. <meta>如果 (1) 和 (2) 不存在,则从页面中的等效标记。
  4. 来自特定于浏览器的猜测启发式,这可能取决于用户设置。

您可以通过读取URL.getConnection().getContentType()并解析出参数来获得(1)。要获得 (2) 或 (3),您必须实际解析文件,这是一个坏消息。(4) 遥不可及。

您可以做的最一致的事情可能就是 Web 浏览器(IE 除外)在将独立网页保存到磁盘时所做的事情:获取所提供的确切原始字节并将它们直接放入文件中,而无需尝试对其进行解码。然后您不必担心编码或行尾更改。这确实意味着 HTTP 标头中的任何字符集元数据都会丢失,但是除了解析 HTML 和<meta>自己插入标签之外,您实际上无能为力(可能太多了)。

InputStream in = url.openStream();
OutputStream out = new FileOutputStream(name + (fileNumber+i) + ".html");

byte[] buffer = new byte[1024*1024];
int len;
while ((len = in.read(buffer)) != -1) {
    out.write(buffer, 0, len);
}

(来自这个问题的nb 缓冲区复制循环,它提供了替代方案,例如IOUtils。)

于 2013-07-16T09:02:14.880 回答