何时使用 Java 中的 Writer 子类;常见做法
我一直对 Java 中不同 IO 实现的数量感到有点困惑,现在我完全陷入了项目开发,同时我花时间阅读有用的东西。
我意识到没有适合新手的比较(除了 Writer 类的 API)位于 Writer
类的不同子类之间。所以我想我应该回避这个问题,这些不同的子类有什么用处?
例如,我通常使用用 BufferedWriter
包装的 FileWriter
来输出到文件,但我一直对没有 println() 感到恼火。
类似的方法,并且必须每隔一行使用 newLine()
(以使输出可读)。 PrintWriter
有 println()
方法,但没有支持附加的构造函数...
如果您能从您的经验中给我两分钱,或者一个您可能偶然发现了很好的指南/操作方法。
编辑:感谢大家的回复,我非常感谢这里传递的信息。有点不幸的是,整个 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). PrintWriter
has 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
java.io
类通常遵循装饰器模式。因此,虽然PrintWriter
没有您可能需要的特定构造函数,但它确实有一个接受另一个Writer
的构造函数,因此您可以执行如下操作:使用注意事项,您总是希望将低级 Writer(例如
FileWriter
或OutputStreamWriter
)包装在BufferedWriter
中,以最大程度地减少实际 IO 操作。然而,这意味着您需要显式地刷新并关闭最外层的Writer,以确保所有内容都被写入。然后您需要在
finally
块中关闭低级Writer,以确保不会泄漏资源。编辑:
看着 MForster 的回答让我重新审视了 FileWriter 的 API。我意识到它不需要明确的字符集,这是一件非常糟糕的事情。因此,我编辑了代码片段,以使用由采用显式字符集的
OutputStreamWriter
包装的FileOutputStream
。The
java.io
classes generally follow the Decorator pattern. So, whilePrintWriter
does not have the specific constructor you might want, it does have a constructor that takes anotherWriter
, so you can do something like the following:As a general usage note, you always want to wrap a low-level Writer (eg
FileWriter
orOutputStreamWriter
) in aBufferedWriter
, 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 anOutputStreamWriter
that takes an explicit character set.FileWriter
通常不是一个可接受的使用类。它不允许您指定用于写入的Charset
,这意味着您只能使用正在运行的平台的默认字符集。不用说,这使得无法一致地使用相同的字符集来读取和写入文本文件,并可能导致数据损坏。您应该将
FileOutputStream
包装在OutputStreamWriter
中,而不是使用FileWriter
。OutputStreamWriter
确实允许您指定字符集:要将
PrintWriter
与上述内容一起使用,只需将BufferedWriter
包装在PrintWriter
中>:您也可以使用带有
File
和字符集名称的PrintWriter
构造函数:这非常适合您的特定情况,实际上与上面的代码做了完全相同的事情,但最好知道如何通过包装各个部分来构建它。
其他 Writer 类型主要用于特殊用途:
CharArrayWriter
与char[]
相同。PipedWriter
用于通过管道传输到PipedReader
。编辑:
我注意到您对另一个关于以这种方式创建作家的冗长性的答案发表了评论。请注意,Guava 等库有助于减少常见操作的冗长性。例如,将
String
写入特定字符集的文件中。使用 Guava 你可以这样写:你也可以创建一个 BufferedWriter ,如下所示:
FileWriter
is generally not an acceptable class to use. It does not allow you to specify theCharset
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 aFileOutputStream
in anOutputStreamWriter
.OutputStreamWriter
does allow you to specify a charset:To use
PrintWriter
with the above, just wrap theBufferedWriter
in aPrintWriter
:You could also just use the
PrintWriter
constructor that takes aFile
and the name of a charset: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 aWriter
that can be used to create aString
.CharArrayWriter
is the same forchar[]
.PipedWriter
for piping to aPipedReader
.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:You can also create a
BufferedWriter
like this:PrintWriter 没有带有“append”参数的构造函数,但 FileWriter 有。在我看来,这就是它所属的地方,这似乎是合乎逻辑的。 PrintWriter 不知道您是否正在写入文件、套接字、控制台、字符串等。在写入套接字时“附加”意味着什么?
因此,做你想做的事情的正确方法很简单:
有趣的旁注:如果你将 OutputStream 包装在 PrintWriter 中,Java 会自动在中间插入 BufferedWriter。但如果将 Writer 包装在 PrintWriter 中,则不会。因此,说:
只要放弃 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:
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:
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.
您可以像这样创建附加的
PrintWriter
:编辑: Anon 的帖子关于在其间使用
BufferedWriter
和指定编码的说法是正确的。You can create an appending
PrintWriter
like this:Edit: Anon's post is right about both using a
BufferedWriter
in between and specifying the encoding.