何时使用 Java 中的 Writer 子类;常见做法

发布于 2024-09-30 06:45:06 字数 934 浏览 0 评论 0原文

我一直对 Java 中不同 IO 实现的数量感到有点困惑,现在我完全陷入了项目开发,同时我花时间阅读有用的东西。

我意识到没有适合新手的比较(除了 Writer 类的 API)位于 Writer 类的不同子类之间。所以我想我应该回避这个问题,这些不同的子类有什么用处?

例如,我通常使用用 BufferedWriter 包装的 FileWriter 来输出到文件,但我一直对没有 println() 感到恼火。 类似的方法,并且必须每隔一行使用 newLine() (以使输出可读)。 PrintWriterprintln() 方法,但没有支持附加的构造函数...

如果您能从您的经验中给我两分钱,或者一个您可能偶然发现了很好的指南/操作方法。

编辑:感谢大家的回复,我非常感谢这里传递的信息。有点不幸的是,整个 append() 事情最终成为焦点,这只是作为一个例子。我的问题主要是指所有不同实现的需求和使用,我想在几个答案中都提到了这一点。

很难选出一个被接受的答案,因为有三个非常可靠的答案,每个答案都有助于我对问题的理解。我必须选择 Anon,因为这次他的代表次数最少。点(我想他是新来的)。他给出了 15 个答案,其中一些答案非常明确,并且提出了 0 个问题。我想说,这是很好的贡献,值得推广。

话虽这么说,ColinD 和 Jay 也提供了非常好的答案,并指出了有趣的想法。尤其是 Jay 关于 Java 自动包装 BufferedWriter 的评论值得注意。再次感谢大家,非常感谢!

I have always been slightly confused with the amount of different IO implementations in Java, and now that I am completely stuck in my project development, I was taking my time to read up on useful stuff meanwhile.

I have realized that there is no newbie-friendly comparison (apart from short explanation at API for Writer class) between the different subclasses of the Writer class. So I figured I'd fire away the question, what are those different subclasses good for?

For example, I usually use a FileWriter wrapped with a BufferedWriter for my outputs to files but I have always been irritated by the fact that there is no println() like method, and one has to use newLine() every second line (to make the output human readable). PrintWriterhas the println() method but no constructor that supports appending however...

I'd really appreciate if you could give me your two cents from your experience, or a nice guide/how-to you might have stumbled upon.

EDIT: Thanks for the replies everyone, I really appreciate the info passed on here. It's a bit unfortunate that the whole append() thing ended up being in focus, it merely meant it as an example. My question was mostly referring to the need and use of all the different implementations, which I guess was mentioned somewhat in a couple of the answers.

It's hard to pick one answer as accepted, since there are three really solid answers, each has contributed to my understanding of the problem. I am gonna have to go with Anon, this time as he's got the least amount of rep. points (I presume he's new on SO). He's 15 answers some of which are really well formulated, and 0 questions asked. Good contribution I'd say, and that is worth promoting.

That being said, ColinD and Jay also provided really good answers, and have pointed out interesting ideas. Especially Jay's comment about Java automatically wrapping a BufferedWriter was worth noting. Thanks again guys, really appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

烟凡古楼 2024-10-07 06:45:06

java.io 类通常遵循装饰器模式。因此,虽然 PrintWriter 没有您可能需要的特定构造函数,但它确实有一个接受另一个 Writer 的构造函数,因此您可以执行如下操作

FileOutputStream fos = null;
try
{
    fos = new FileOutputStream("foo.txt");
    PrintWriter out = new PrintWriter(
                          new BufferedWriter(
                              new OutputStreamWriter(fos, "UTF-8")));
    // do what you want to do
    out.flush();
    out.close();
}
finally
{
    // quietly close the FileOutputStream (see Jakarta Commons IOUtils)
}

:使用注意事项,您总是希望将低级 Writer(例如 FileWriterOutputStreamWriter)包装在 BufferedWriter 中,以最大程度地减少实际 IO 操作。然而,这意味着您需要显式地刷新并关闭最外层的Writer,以确保所有内容都被写入。

然后您需要在finally块中关闭低级Writer,以确保不会泄漏资源。

编辑

看着 MForster 的回答让我重新审视了 FileWriter 的 API。我意识到它不需要明确的字符集,这是一件非常糟糕的事情。因此,我编辑了代码片段,以使用由采用显式字符集的 OutputStreamWriter 包装的 FileOutputStream

The java.io classes generally follow the Decorator pattern. So, while PrintWriter does not have the specific constructor you might want, it does have a constructor that takes another Writer, so you can do something like the following:

FileOutputStream fos = null;
try
{
    fos = new FileOutputStream("foo.txt");
    PrintWriter out = new PrintWriter(
                          new BufferedWriter(
                              new OutputStreamWriter(fos, "UTF-8")));
    // do what you want to do
    out.flush();
    out.close();
}
finally
{
    // quietly close the FileOutputStream (see Jakarta Commons IOUtils)
}

As a general usage note, you always want to wrap a low-level Writer (eg FileWriter or OutputStreamWriter) in a BufferedWriter, to minimize actual IO operations. However, this means that you need to explicitly flush and close the outermost Writer, to ensure that all content is written.

And then you need to close the low-level Writer in a finally block, to ensure that you don't leak resources.

Edit:

Looking at MForster's answer made me take another look at the API for FileWriter. And I realized that it doesn't take an explicit character set, which is a Very Bad Thing. So I've edited my code snippet to use a FileOutputStream wrapped by an OutputStreamWriter that takes an explicit character set.

桃扇骨 2024-10-07 06:45:06

FileWriter 通常不是一个可接受的使用类。它不允许您指定用于写入的 Charset,这意味着您只能使用正在运行的平台的默认字符集。不用说,这使得无法一致地使用相同的字符集来读取和写入文本文件,并可能导致数据损坏。

您应该将 FileOutputStream 包装在 OutputStreamWriter 中,而不是使用 FileWriterOutputStreamWriter 确实允许您指定字符集:

File file = ...
OutputStream fileOut = new FileOutputStream(file);
Writer writer = new BufferedWriter(new OutputStreamWriter(fileOut, "UTF-8"));

要将 PrintWriter 与上述内容一起使用,只需将 BufferedWriter 包装在 PrintWriter 中>:

PrintWriter printWriter = new PrintWriter(writer);

您也可以使用带有 File 和字符集名称的 PrintWriter 构造函数:

PrintWriter printWriter = new PrintWriter(file, "UTF-8");

这非常适合您的特定情况,实际上与上面的代码做了完全相同的事情,但最好知道如何通过包装各个部分来构建它。

其他 Writer 类型主要用于特殊用途:

  • StringWriter 只是一个可用于创建 String 的 Writer >。 CharArrayWriterchar[] 相同。
  • PipedWriter 用于通过管道传输到 PipedReader

编辑:

我注意到您对另一个关于以这种方式创建作家的冗长性的答案发表了评论。请注意,Guava 等库有助于减少常见操作的冗长性。例如,将 String 写入特定字符集的文件中。使用 Guava 你可以这样写:

Files.write(text, file, Charsets.UTF_8);

你也可以创建一个 BufferedWriter ,如下所示:

BufferedWriter writer = Files.newWriter(file, Charsets.UTF_8);

FileWriter is generally not an acceptable class to use. It does not allow you to specify the Charset to use for writing, which means you are stuck with whatever the default charset of the platform you're running on happens to be. Needless to say, this makes it impossible to consistently use the same charset for reading and writing text files and can lead to corrupted data.

Rather than using FileWriter, you should be wrapping a FileOutputStream in an OutputStreamWriter. OutputStreamWriter does allow you to specify a charset:

File file = ...
OutputStream fileOut = new FileOutputStream(file);
Writer writer = new BufferedWriter(new OutputStreamWriter(fileOut, "UTF-8"));

To use PrintWriter with the above, just wrap the BufferedWriter in a PrintWriter:

PrintWriter printWriter = new PrintWriter(writer);

You could also just use the PrintWriter constructor that takes a File and the name of a charset:

PrintWriter printWriter = new PrintWriter(file, "UTF-8");

This works just fine for your particular situation, and actually does the exact same thing as the code above, but it's good to know how to build it by wrapping the various parts.

The other Writer types are mostly for specialized uses:

  • StringWriter is just a Writer that can be used to create a String. CharArrayWriter is the same for char[].
  • PipedWriter for piping to a PipedReader.

Edit:

I noticed that you commented on another answer about the verbosity of creating a writer this way. Note that there are libraries such as Guava that help reduce the verbosity of common operations. Take, for example, writing a String to a file in a specific charset. With Guava you can just write:

Files.write(text, file, Charsets.UTF_8);

You can also create a BufferedWriter like this:

BufferedWriter writer = Files.newWriter(file, Charsets.UTF_8);
若水般的淡然安静女子 2024-10-07 06:45:06

PrintWriter 没有带有“append”参数的构造函数,但 FileWriter 有。在我看来,这就是它所属的地方,这似乎是合乎逻辑的。 PrintWriter 不知道您是否正在写入文件、套接字、控制台、字符串等。在写入套接字时“附加”意味着什么?

因此,做你想做的事情的正确方法很简单:

PrintWriter out=new PrintWriter(new BufferedWriter(new FileWriter(myfile, append)));

有趣的旁注:如果你将 OutputStream 包装在 PrintWriter 中,Java 会自动在中间插入 BufferedWriter。但如果将 Writer 包装在 PrintWriter 中,则不会。因此,说:

PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(myfile))));

只要放弃 BufferedWriter 和 OutputStreamWriter,无论如何你都可以免费获得它们,这是没有任何好处的。我不知道这种不一致是否有什么充分的理由。

确实,您不能像 ColinD 注释那样在 FileWriter 中指定字符编码。我不知道这是否会导致“不可接受”。我几乎总是非常乐意接受默认编码。如果您使用英语以外的语言,这可能是一个问题。

当我第一次开始使用 Java 时,分层包装 Writers 或 OutputStreams 的需求让我感到困惑。但一旦你掌握了它的窍门,那就没什么大不了的了。你只需要将你的思想投入到编写框架中即可。每个作家都有一个职能。可以这样想,我想打印到文件,所以我需要将 FileWriter 包装在 PrintWriter 中。或者,我想将输出流转换为编写器,因此我需要一个 OutputStreamWriter。等等。

或者也许您只是习惯了一直使用的那些。弄清楚一次并记住你是如何做到的。

PrintWriter doesn't have a constructor that takes an "append" parameter, but FileWriter does. And it seems logical to me that that's where it belongs. PrintWriter doesn't know if you're writing to a file, a socket, the console, a string, etc. What would it mean to "append" on writes to a socket?

So the right way to do what you want is simply:

PrintWriter out=new PrintWriter(new BufferedWriter(new FileWriter(myfile, append)));

Interesting side note: If you wrap an OutputStream in a PrintWriter, Java automatically inserts a BufferedWriter in the middle. But if you wrap a Writer in a PrintWriter, it does not. So nothing is gained by saying:

PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(myfile))));

Just leave off the BufferedWriter and the OutputStreamWriter, you get them for free anyway. I have no idea if there is some good reason for the inconsistency.

It's true that you can't specify a character encoding in a FileWriter as ColinD notes. I don't know that that makes it "unacceptable". I almost always am perfectly happy to accept the default encoding. Maybe if you're using a language other than English this is an issue.

The need to wrap Writers or OutputStreams in layers was confusing to me when I first started using Java. But once you get the hang of it, it's no big deal. You just have to bend your mind into the write framework. Each writer has a function. Think of it like, I want to print to a file, so I need to wrap a FileWriter in a PrintWriter. Or, I want to convert an output stream to a writer, so I need an OutputStreamWriter. Etc.

Or maybe you just get used to the ones you use all the time. Figure it out once and remember how you did it.

悍妇囚夫 2024-10-07 06:45:06

您可以像这样创建附加的 PrintWriter

OutputStream os = new FileOutputStream("/tmp/out", true);
PrintWriter writer = new PrintWriter(os);

编辑: Anon 的帖子关于在其间使用 BufferedWriter 和指定编码的说法是正确的。

You can create an appending PrintWriter like this:

OutputStream os = new FileOutputStream("/tmp/out", true);
PrintWriter writer = new PrintWriter(os);

Edit: Anon's post is right about both using a BufferedWriter in between and specifying the encoding.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文