java的PrintStream(打印输出流)详解(java_io)

本章介绍PrintStream以及 它与DataOutputStream的区别。我们先对PrintStream有个大致认识,然后再深入学习它的源码,最后通过示例加深对它的了解。

PrintStream 介绍

PrintStream 是打印输出流,它继承于FilterOutputStream。
PrintStream 是用来装饰其它输出流。它能为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
与其他输出流不同,PrintStream 永远不会抛出 IOException;它产生的IOException会被自身的函数所捕获并设置错误标记, 用户可以通过 checkError() 返回错误标记,从而查看PrintStream内部是否产生了IOException。
另外,PrintStream 提供了自动flush 和 字符集设置功能。所谓自动flush,就是往PrintStream写入的数据会立刻调用flush()函数。

PrintStream 函数列表

  1. /*
  2. * 构造函数
  3. */
  4. // 将“输出流out”作为PrintStream的输出流,不会自动flush,并且采用默认字符集
  5. // 所谓“自动flush”,就是每次执行print(), println(), write()函数,都会调用flush()函数;
  6. // 而“不自动flush”,则需要我们手动调用flush()接口。
  7. PrintStream(OutputStream out)
  8. // 将“输出流out”作为PrintStream的输出流,自动flush,并且采用默认字符集。
  9. PrintStream(OutputStream out, boolean autoFlush)
  10. // 将“输出流out”作为PrintStream的输出流,自动flush,采用charsetName字符集。
  11. PrintStream(OutputStream out, boolean autoFlush, String charsetName)
  12. // 创建file对应的FileOutputStream,然后将该FileOutputStream作为PrintStream的输出流,不自动flush,采用默认字符集。
  13. PrintStream(File file)
  14. // 创建file对应的FileOutputStream,然后将该FileOutputStream作为PrintStream的输出流,不自动flush,采用charsetName字符集。
  15. PrintStream(File file, String charsetName)
  16. // 创建fileName对应的FileOutputStream,然后将该FileOutputStream作为PrintStream的输出流,不自动flush,采用默认字符集。
  17. PrintStream(String fileName)
  18. // 创建fileName对应的FileOutputStream,然后将该FileOutputStream作为PrintStream的输出流,不自动flush,采用charsetName字符集。
  19. PrintStream(String fileName, String charsetName)
  20.  
  21. // 将“字符c”追加到“PrintStream输出流中”
  22. PrintStream append(char c)
  23. // 将“字符序列从start(包括)到end(不包括)的全部字符”追加到“PrintStream输出流中”
  24. PrintStream append(CharSequence charSequence, int start, int end)
  25. // 将“字符序列的全部字符”追加到“PrintStream输出流中”
  26. PrintStream append(CharSequence charSequence)
  27. // flush“PrintStream输出流缓冲中的数据”,并检查错误
  28. boolean checkError()
  29. // 关闭“PrintStream输出流”
  30. synchronized void close()
  31. // flush“PrintStream输出流缓冲中的数据”。
  32. // 例如,PrintStream装饰的是FileOutputStream,则调用flush时会将数据写入到文件中
  33. synchronized void flush()
  34. // 根据“Locale值(区域属性)”来格式化数据
  35. PrintStream format(Locale l, String format, Object... args)
  36. // 根据“默认的Locale值(区域属性)”来格式化数据
  37. PrintStream format(String format, Object... args)
  38. // 将“float数据f对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  39. void print(float f)
  40. // 将“double数据d对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  41. void print(double d)
  42. // 将“字符串数据str”写入到“PrintStream输出流”中,print实际调用的是write函数
  43. synchronized void print(String str)
  44. // 将“对象o对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  45. void print(Object o)
  46. // 将“字符c对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  47. void print(char c)
  48. // 将“字符数组chars对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  49. void print(char[] chars)
  50. // 将“long型数据l对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  51. void print(long l)
  52. // 将“int数据i对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  53. void print(int i)
  54. // 将“boolean数据b对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  55. void print(boolean b)
  56. // 将“数据args”根据“Locale值(区域属性)”按照format格式化,并写入到“PrintStream输出流”中
  57. PrintStream printf(Locale l, String format, Object... args)
  58. // 将“数据args”根据“默认Locale值(区域属性)”按照format格式化,并写入到“PrintStream输出流”中
  59. PrintStream printf(String format, Object... args)
  60. // 将“换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  61. void println()
  62. // 将“float数据对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  63. void println(float f)
  64. // 将“int数据对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  65. void println(int i)
  66. // 将“long数据对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  67. void println(long l)
  68. // 将“对象o对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  69. void println(Object o)
  70. // 将“字符数组chars对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  71. void println(char[] chars)
  72. // 将“字符串str+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  73. synchronized void println(String str)
  74. // 将“字符c对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  75. void println(char c)
  76. // 将“double数据对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  77. void println(double d)
  78. // 将“boolean数据对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  79. void println(boolean b)
  80. // 将数据oneByte写入到“PrintStream输出流”中。oneByte虽然是int类型,但实际只会写入一个字节
  81. synchronized void write(int oneByte)
  82. // 将“buffer中从offset开始的length个字节”写入到“PrintStream输出流”中。
  83. void write(byte[] buffer, int offset, int length)

注意print()和println()都是将其中参数转换成字符串之后,再写入到输入流。
例如,

  1. print(0x61);

等价于

  1. write(String.valueOf(0x61));

上面语句是将字符串"97"写入到输出流。0x61对应十进制数是97。

  1. write(0x61)

上面语句是将字符'a'写入到输出流。因为0x61对应的ASCII码的字母'a'。

查看下面的代码,我们能对这些函数有更清晰的认识!

PrintStream 源码分析(基于jdk1.7.40)

  1. 1 package java.io;
  2. 2
  3. 3 import java.util.Formatter;
  4. 4 import java.util.Locale;
  5. 5 import java.nio.charset.Charset;
  6. 6 import java.nio.charset.IllegalCharsetNameException;
  7. 7 import java.nio.charset.UnsupportedCharsetException;
  8. 8
  9. 9 public class PrintStream extends FilterOutputStream
  10. 10 implements Appendable, Closeable
  11. 11 {
  12. 12
  13. 13 // 自动flush
  14. 14 // 所谓“自动flush”,就是每次执行print(), println(), write()函数,都会调用flush()函数;
  15. 15 // 而“不自动flush”,则需要我们手动调用flush()接口。
  16. 16 private final boolean autoFlush;
  17. 17 // PrintStream是否右产生异常。当PrintStream有异常产生时,会被本身捕获,并设置trouble为true
  18. 18 private boolean trouble = false;
  19. 19 // 用于格式化的对象
  20. 20 private Formatter formatter;
  21. 21
  22. 22 // BufferedWriter对象,用于实现“PrintStream支持字符集”。
  23. 23 // 因为PrintStream是OutputStream的子类,所以它本身不支持字符串;
  24. 24 // 但是BufferedWriter支持字符集,因此可以通过OutputStreamWriter创建PrintStream对应的BufferedWriter对象,从而支持字符集。
  25. 25 private BufferedWriter textOut;
  26. 26 private OutputStreamWriter charOut;
  27. 27
  28. 28 private static <T> T requireNonNull(T obj, String message) {
  29. 29 if (obj == null)
  30. 30 throw new NullPointerException(message);
  31. 31 return obj;
  32. 32 }
  33. 33
  34. 34 // 返回csn对应的字符集对象
  35. 35 private static Charset toCharset(String csn)
  36. 36 throws UnsupportedEncodingException
  37. 37 {
  38. 38 requireNonNull(csn, "charsetName");
  39. 39 try {
  40. 40 return Charset.forName(csn);
  41. 41 } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
  42. 42 // UnsupportedEncodingException should be thrown
  43. 43 throw new UnsupportedEncodingException(csn);
  44. 44 }
  45. 45 }
  46. 46
  47. 47 // 将“输出流out”作为PrintStream的输出流,autoFlush的flush模式,并且采用默认字符集。
  48. 48 private PrintStream(boolean autoFlush, OutputStream out) {
  49. 49 super(out);
  50. 50 this.autoFlush = autoFlush;
  51. 51 this.charOut = new OutputStreamWriter(this);
  52. 52 this.textOut = new BufferedWriter(charOut);
  53. 53 }
  54. 54
  55. 55 // 将“输出流out”作为PrintStream的输出流,自动flush,采用charsetName字符集。
  56. 56 private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {
  57. 57 super(out);
  58. 58 this.autoFlush = autoFlush;
  59. 59 this.charOut = new OutputStreamWriter(this, charset);
  60. 60 this.textOut = new BufferedWriter(charOut);
  61. 61 }
  62. 62
  63. 63 // 将“输出流out”作为PrintStream的输出流,自动flush,采用charsetName字符集。
  64. 64 private PrintStream(boolean autoFlush, Charset charset, OutputStream out)
  65. 65 throws UnsupportedEncodingException
  66. 66 {
  67. 67 this(autoFlush, out, charset);
  68. 68 }
  69. 69
  70. 70 // 将“输出流out”作为PrintStream的输出流,不会自动flush,并且采用默认字符集
  71. 71 public PrintStream(OutputStream out) {
  72. 72 this(out, false);
  73. 73 }
  74. 74
  75. 75 // 将“输出流out”作为PrintStream的输出流,自动flush,并且采用默认字符集。
  76. 76 public PrintStream(OutputStream out, boolean autoFlush) {
  77. 77 this(autoFlush, requireNonNull(out, "Null output stream"));
  78. 78 }
  79. 79
  80. 80 // 将“输出流out”作为PrintStream的输出流,自动flush,采用charsetName字符集。
  81. 81 public PrintStream(OutputStream out, boolean autoFlush, String encoding)
  82. 82 throws UnsupportedEncodingException
  83. 83 {
  84. 84 this(autoFlush,
  85. 85 requireNonNull(out, "Null output stream"),
  86. 86 toCharset(encoding));
  87. 87 }
  88. 88
  89. 89 // 创建fileName对应的FileOutputStream,然后将该FileOutputStream作为PrintStream的输出流,不自动flush,采用默认字符集。
  90. 90 public PrintStream(String fileName) throws FileNotFoundException {
  91. 91 this(false, new FileOutputStream(fileName));
  92. 92 }
  93. 93
  94. 94 // 创建fileName对应的FileOutputStream,然后将该FileOutputStream作为PrintStream的输出流,不自动flush,采用charsetName字符集。
  95. 95 public PrintStream(String fileName, String csn)
  96. 96 throws FileNotFoundException, UnsupportedEncodingException
  97. 97 {
  98. 98 // ensure charset is checked before the file is opened
  99. 99 this(false, toCharset(csn), new FileOutputStream(fileName));
  100. 100 }
  101. 101
  102. 102 // 创建file对应的FileOutputStream,然后将该FileOutputStream作为PrintStream的输出流,不自动flush,采用默认字符集。
  103. 103 public PrintStream(File file) throws FileNotFoundException {
  104. 104 this(false, new FileOutputStream(file));
  105. 105 }
  106. 106
  107. 107 // 创建file对应的FileOutputStream,然后将该FileOutputStream作为PrintStream的输出流,不自动flush,采用csn字符集。
  108. 108 public PrintStream(File file, String csn)
  109. 109 throws FileNotFoundException, UnsupportedEncodingException
  110. 110 {
  111. 111 // ensure charset is checked before the file is opened
  112. 112 this(false, toCharset(csn), new FileOutputStream(file));
  113. 113 }
  114. 114
  115. 115 private void ensureOpen() throws IOException {
  116. 116 if (out == null)
  117. 117 throw new IOException("Stream closed");
  118. 118 }
  119. 119
  120. 120 // flush“PrintStream输出流缓冲中的数据”。
  121. 121 // 例如,PrintStream装饰的是FileOutputStream,则调用flush时会将数据写入到文件中
  122. 122 public void flush() {
  123. 123 synchronized (this) {
  124. 124 try {
  125. 125 ensureOpen();
  126. 126 out.flush();
  127. 127 }
  128. 128 catch (IOException x) {
  129. 129 trouble = true;
  130. 130 }
  131. 131 }
  132. 132 }
  133. 133
  134. 134 private boolean closing = false; /* To avoid recursive closing */
  135. 135
  136. 136 // 关闭PrintStream
  137. 137 public void close() {
  138. 138 synchronized (this) {
  139. 139 if (! closing) {
  140. 140 closing = true;
  141. 141 try {
  142. 142 textOut.close();
  143. 143 out.close();
  144. 144 }
  145. 145 catch (IOException x) {
  146. 146 trouble = true;
  147. 147 }
  148. 148 textOut = null;
  149. 149 charOut = null;
  150. 150 out = null;
  151. 151 }
  152. 152 }
  153. 153 }
  154. 154
  155. 155 // flush“PrintStream输出流缓冲中的数据”,并检查错误
  156. 156 public boolean checkError() {
  157. 157 if (out != null)
  158. 158 flush();
  159. 159 if (out instanceof java.io.PrintStream) {
  160. 160 PrintStream ps = (PrintStream) out;
  161. 161 return ps.checkError();
  162. 162 }
  163. 163 return trouble;
  164. 164 }
  165. 165
  166. 166 protected void setError() {
  167. 167 trouble = true;
  168. 168 }
  169. 169
  170. 170 protected void clearError() {
  171. 171 trouble = false;
  172. 172 }
  173. 173
  174. 174 // 将数据b写入到“PrintStream输出流”中。b虽然是int类型,但实际只会写入一个字节
  175. 175 public void write(int b) {
  176. 176 try {
  177. 177 synchronized (this) {
  178. 178 ensureOpen();
  179. 179 out.write(b);
  180. 180 if ((b == '\n') && autoFlush)
  181. 181 out.flush();
  182. 182 }
  183. 183 }
  184. 184 catch (InterruptedIOException x) {
  185. 185 Thread.currentThread().interrupt();
  186. 186 }
  187. 187 catch (IOException x) {
  188. 188 trouble = true;
  189. 189 }
  190. 190 }
  191. 191
  192. 192 // 将“buf中从off开始的length个字节”写入到“PrintStream输出流”中。
  193. 193 public void write(byte buf[], int off, int len) {
  194. 194 try {
  195. 195 synchronized (this) {
  196. 196 ensureOpen();
  197. 197 out.write(buf, off, len);
  198. 198 if (autoFlush)
  199. 199 out.flush();
  200. 200 }
  201. 201 }
  202. 202 catch (InterruptedIOException x) {
  203. 203 Thread.currentThread().interrupt();
  204. 204 }
  205. 205 catch (IOException x) {
  206. 206 trouble = true;
  207. 207 }
  208. 208 }
  209. 209
  210. 210 // 将“buf中的全部数据”写入到“PrintStream输出流”中。
  211. 211 private void write(char buf[]) {
  212. 212 try {
  213. 213 synchronized (this) {
  214. 214 ensureOpen();
  215. 215 textOut.write(buf);
  216. 216 textOut.flushBuffer();
  217. 217 charOut.flushBuffer();
  218. 218 if (autoFlush) {
  219. 219 for (int i = 0; i < buf.length; i++)
  220. 220 if (buf[i] == '\n')
  221. 221 out.flush();
  222. 222 }
  223. 223 }
  224. 224 }
  225. 225 catch (InterruptedIOException x) {
  226. 226 Thread.currentThread().interrupt();
  227. 227 }
  228. 228 catch (IOException x) {
  229. 229 trouble = true;
  230. 230 }
  231. 231 }
  232. 232
  233. 233 // 将“字符串s”写入到“PrintStream输出流”中。
  234. 234 private void write(String s) {
  235. 235 try {
  236. 236 synchronized (this) {
  237. 237 ensureOpen();
  238. 238 textOut.write(s);
  239. 239 textOut.flushBuffer();
  240. 240 charOut.flushBuffer();
  241. 241 if (autoFlush && (s.indexOf('\n') >= 0))
  242. 242 out.flush();
  243. 243 }
  244. 244 }
  245. 245 catch (InterruptedIOException x) {
  246. 246 Thread.currentThread().interrupt();
  247. 247 }
  248. 248 catch (IOException x) {
  249. 249 trouble = true;
  250. 250 }
  251. 251 }
  252. 252
  253. 253 // 将“换行符”写入到“PrintStream输出流”中。
  254. 254 private void newLine() {
  255. 255 try {
  256. 256 synchronized (this) {
  257. 257 ensureOpen();
  258. 258 textOut.newLine();
  259. 259 textOut.flushBuffer();
  260. 260 charOut.flushBuffer();
  261. 261 if (autoFlush)
  262. 262 out.flush();
  263. 263 }
  264. 264 }
  265. 265 catch (InterruptedIOException x) {
  266. 266 Thread.currentThread().interrupt();
  267. 267 }
  268. 268 catch (IOException x) {
  269. 269 trouble = true;
  270. 270 }
  271. 271 }
  272. 272
  273. 273 // 将“boolean数据对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  274. 274 public void print(boolean b) {
  275. 275 write(b ? "true" : "false");
  276. 276 }
  277. 277
  278. 278 // 将“字符c对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  279. 279 public void print(char c) {
  280. 280 write(String.valueOf(c));
  281. 281 }
  282. 282
  283. 283 // 将“int数据i对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  284. 284 public void print(int i) {
  285. 285 write(String.valueOf(i));
  286. 286 }
  287. 287
  288. 288 // 将“long型数据l对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  289. 289 public void print(long l) {
  290. 290 write(String.valueOf(l));
  291. 291 }
  292. 292
  293. 293 // 将“float数据f对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  294. 294 public void print(float f) {
  295. 295 write(String.valueOf(f));
  296. 296 }
  297. 297
  298. 298 // 将“double数据d对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  299. 299 public void print(double d) {
  300. 300 write(String.valueOf(d));
  301. 301 }
  302. 302
  303. 303 // 将“字符数组s”写入到“PrintStream输出流”中,print实际调用的是write函数
  304. 304 public void print(char s[]) {
  305. 305 write(s);
  306. 306 }
  307. 307
  308. 308 // 将“字符串数据s”写入到“PrintStream输出流”中,print实际调用的是write函数
  309. 309 public void print(String s) {
  310. 310 if (s == null) {
  311. 311 s = "null";
  312. 312 }
  313. 313 write(s);
  314. 314 }
  315. 315
  316. 316 // 将“对象obj对应的字符串”写入到“PrintStream输出流”中,print实际调用的是write函数
  317. 317 public void print(Object obj) {
  318. 318 write(String.valueOf(obj));
  319. 319 }
  320. 320
  321. 321
  322. 322 // 将“换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  323. 323 public void println() {
  324. 324 newLine();
  325. 325 }
  326. 326
  327. 327 // 将“boolean数据对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  328. 328 public void println(boolean x) {
  329. 329 synchronized (this) {
  330. 330 print(x);
  331. 331 newLine();
  332. 332 }
  333. 333 }
  334. 334
  335. 335 // 将“字符x对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  336. 336 public void println(char x) {
  337. 337 synchronized (this) {
  338. 338 print(x);
  339. 339 newLine();
  340. 340 }
  341. 341 }
  342. 342
  343. 343 // 将“int数据对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  344. 344 public void println(int x) {
  345. 345 synchronized (this) {
  346. 346 print(x);
  347. 347 newLine();
  348. 348 }
  349. 349 }
  350. 350
  351. 351 // 将“long数据对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  352. 352 public void println(long x) {
  353. 353 synchronized (this) {
  354. 354 print(x);
  355. 355 newLine();
  356. 356 }
  357. 357 }
  358. 358
  359. 359 // 将“float数据对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  360. 360 public void println(float x) {
  361. 361 synchronized (this) {
  362. 362 print(x);
  363. 363 newLine();
  364. 364 }
  365. 365 }
  366. 366
  367. 367 // 将“double数据对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  368. 368 public void println(double x) {
  369. 369 synchronized (this) {
  370. 370 print(x);
  371. 371 newLine();
  372. 372 }
  373. 373 }
  374. 374
  375. 375 // 将“字符数组x+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  376. 376 public void println(char x[]) {
  377. 377 synchronized (this) {
  378. 378 print(x);
  379. 379 newLine();
  380. 380 }
  381. 381 }
  382. 382
  383. 383 // 将“字符串x+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  384. 384 public void println(String x) {
  385. 385 synchronized (this) {
  386. 386 print(x);
  387. 387 newLine();
  388. 388 }
  389. 389 }
  390. 390
  391. 391 // 将“对象o对应的字符串+换行符”写入到“PrintStream输出流”中,println实际调用的是write函数
  392. 392 public void println(Object x) {
  393. 393 String s = String.valueOf(x);
  394. 394 synchronized (this) {
  395. 395 print(s);
  396. 396 newLine();
  397. 397 }
  398. 398 }
  399. 399
  400. 400 // 将“数据args”根据“默认Locale值(区域属性)”按照format格式化,并写入到“PrintStream输出流”中
  401. 401 public PrintStream printf(String format, Object ... args) {
  402. 402 return format(format, args);
  403. 403 }
  404. 404
  405. 405 // 将“数据args”根据“Locale值(区域属性)”按照format格式化,并写入到“PrintStream输出流”中
  406. 406 public PrintStream printf(Locale l, String format, Object ... args) {
  407. 407 return format(l, format, args);
  408. 408 }
  409. 409
  410. 410 // 根据“默认的Locale值(区域属性)”来格式化数据
  411. 411 public PrintStream format(String format, Object ... args) {
  412. 412 try {
  413. 413 synchronized (this) {
  414. 414 ensureOpen();
  415. 415 if ((formatter == null)
  416. 416 || (formatter.locale() != Locale.getDefault()))
  417. 417 formatter = new Formatter((Appendable) this);
  418. 418 formatter.format(Locale.getDefault(), format, args);
  419. 419 }
  420. 420 } catch (InterruptedIOException x) {
  421. 421 Thread.currentThread().interrupt();
  422. 422 } catch (IOException x) {
  423. 423 trouble = true;
  424. 424 }
  425. 425 return this;
  426. 426 }
  427. 427
  428. 428 // 根据“Locale值(区域属性)”来格式化数据
  429. 429 public PrintStream format(Locale l, String format, Object ... args) {
  430. 430 try {
  431. 431 synchronized (this) {
  432. 432 ensureOpen();
  433. 433 if ((formatter == null)
  434. 434 || (formatter.locale() != l))
  435. 435 formatter = new Formatter(this, l);
  436. 436 formatter.format(l, format, args);
  437. 437 }
  438. 438 } catch (InterruptedIOException x) {
  439. 439 Thread.currentThread().interrupt();
  440. 440 } catch (IOException x) {
  441. 441 trouble = true;
  442. 442 }
  443. 443 return this;
  444. 444 }
  445. 445
  446. 446 // 将“字符序列的全部字符”追加到“PrintStream输出流中”
  447. 447 public PrintStream append(CharSequence csq) {
  448. 448 if (csq == null)
  449. 449 print("null");
  450. 450 else
  451. 451 print(csq.toString());
  452. 452 return this;
  453. 453 }
  454. 454
  455. 455 // 将“字符序列从start(包括)到end(不包括)的全部字符”追加到“PrintStream输出流中”
  456. 456 public PrintStream append(CharSequence csq, int start, int end) {
  457. 457 CharSequence cs = (csq == null ? "null" : csq);
  458. 458 write(cs.subSequence(start, end).toString());
  459. 459 return this;
  460. 460 }
  461. 461
  462. 462 // 将“字符c”追加到“PrintStream输出流中”
  463. 463 public PrintStream append(char c) {
  464. 464 print(c);
  465. 465 return this;
  466. 466 }
  467. 467 }

说明
PrintStream的源码比较简单,请上文的注释进行阅读。若有不明白的地方,建议先看看后面的PrintStream使用示例;待搞清它的作用和用法之后,再来阅读源码。

PrintStream和DataOutputStream异同点

相同点:都是继承与FileOutputStream,用于包装其它输出流。

不同点

(01) PrintStream和DataOutputStream 都可以将数据格式化输出;但它们在“输出字符串”时的编码不同。

PrintStream是输出时采用的是用户指定的编码(创建PrintStream时指定的),若没有指定,则采用系统默认的字符编码。而DataOutputStream则采用的是UTF-8。 
      关于UTF-8的字符编码可以参考“字符编码(ASCII,Unicode和UTF-8) 和 大小端
      关于DataOutputStream的更多内容,可以参考“java io系列15之 DataOutputStream(数据输出流)的认知、源码和示例

(02) 它们的写入数据时的异常处理机制不同。

DataOutputStream在通过write()向“输出流”中写入数据时,若产生IOException,会抛出。
       而PrintStream在通过write()向“输出流”中写入数据时,若产生IOException,则会在write()中进行捕获处理;并设置trouble标记(用于表示产生了异常)为true。用户可以通过checkError()返回trouble值,从而检查输出流中是否产生了异常。

(03) 构造函数不同

DataOutputStream的构造函数只有一个:DataOutputStream(OutputStream out)。即它只支持以输出流out作为“DataOutputStream的输出流”。
       而PrintStream的构造函数有许多:和DataOutputStream一样,支持以输出流out作为“PrintStream输出流”的构造函数;还支持以“File对象”或者“String类型的文件名对象”的构造函数。
       而且,在PrintStream的构造函数中,能“指定字符集”和“是否支持自动flush()操作”。

(04) 目的不同

DataOutputStream的作用是装饰其它的输出流,它和DataInputStream配合使用:允许应用程序以与机器无关的方式从底层输入流中读写java数据类型。
       而PrintStream的作用虽然也是装饰其他输出流,但是它的目的不是以与机器无关的方式从底层读写java数据类型;而是为其它输出流提供打印各种数据值表示形式,使其它输出流能方便的通过print(), println()或printf()等输出各种格式的数据。

示例代码

关于PrintStream中API的详细用法,参考示例代码(PrintStreamTest.java)

  1. 1 import java.io.PrintStream;
  2. 2 import java.io.File;
  3. 3 import java.io.FileOutputStream;
  4. 4 import java.io.IOException;
  5. 5
  6. 6 /**
  7. 7 * PrintStream 的示例程序
  8. 8 *
  9. 9 * @author skywang
  10. 10 */
  11. 11 public class PrintStreamTest {
  12. 12
  13. 13 public static void main(String[] args) {
  14. 14
  15. 15 // 下面3个函数的作用都是一样:都是将字母“abcde”写入到文件“file.txt”中。
  16. 16 // 任选一个执行即可!
  17. 17 testPrintStreamConstrutor1() ;
  18. 18 //testPrintStreamConstrutor2() ;
  19. 19 //testPrintStreamConstrutor3() ;
  20. 20
  21. 21 // 测试write(), print(), println(), printf()等接口。
  22. 22 testPrintStreamAPIS() ;
  23. 23 }
  24. 24
  25. 25 /**
  26. 26 * PrintStream(OutputStream out) 的测试函数
  27. 27 *
  28. 28 * 函数的作用,就是将字母“abcde”写入到文件“file.txt”中
  29. 29 */
  30. 30 private static void testPrintStreamConstrutor1() {
  31. 31 // 0x61对应ASCII码的字母'a',0x62对应ASCII码的字母'b', ...
  32. 32 final byte[] arr={0x61, 0x62, 0x63, 0x64, 0x65 }; // abced
  33. 33 try {
  34. 34 // 创建文件“file.txt”的File对象
  35. 35 File file = new File("file.txt");
  36. 36 // 创建文件对应FileOutputStream
  37. 37 PrintStream out = new PrintStream(
  38. 38 new FileOutputStream(file));
  39. 39 // 将“字节数组arr”全部写入到输出流中
  40. 40 out.write(arr);
  41. 41 // 关闭输出流
  42. 42 out.close();
  43. 43 } catch (IOException e) {
  44. 44 e.printStackTrace();
  45. 45 }
  46. 46 }
  47. 47
  48. 48 /**
  49. 49 * PrintStream(File file) 的测试函数
  50. 50 *
  51. 51 * 函数的作用,就是将字母“abcde”写入到文件“file.txt”中
  52. 52 */
  53. 53 private static void testPrintStreamConstrutor2() {
  54. 54 final byte[] arr={0x61, 0x62, 0x63, 0x64, 0x65 };
  55. 55 try {
  56. 56 File file = new File("file.txt");
  57. 57 PrintStream out = new PrintStream(file);
  58. 58 out.write(arr);
  59. 59 out.close();
  60. 60 } catch (IOException e) {
  61. 61 e.printStackTrace();
  62. 62 }
  63. 63 }
  64. 64
  65. 65 /**
  66. 66 * PrintStream(String fileName) 的测试函数
  67. 67 *
  68. 68 * 函数的作用,就是将字母“abcde”写入到文件“file.txt”中
  69. 69 */
  70. 70 private static void testPrintStreamConstrutor3() {
  71. 71 final byte[] arr={0x61, 0x62, 0x63, 0x64, 0x65 };
  72. 72 try {
  73. 73 PrintStream out = new PrintStream("file.txt");
  74. 74 out.write(arr);
  75. 75 out.close();
  76. 76 } catch (IOException e) {
  77. 77 e.printStackTrace();
  78. 78 }
  79. 79 }
  80. 80
  81. 81 /**
  82. 82 * 测试write(), print(), println(), printf()等接口。
  83. 83 */
  84. 84 private static void testPrintStreamAPIS() {
  85. 85 // 0x61对应ASCII码的字母'a',0x62对应ASCII码的字母'b', ...
  86. 86 final byte[] arr={0x61, 0x62, 0x63, 0x64, 0x65 }; // abced
  87. 87 try {
  88. 88 // 创建文件对应FileOutputStream
  89. 89 PrintStream out = new PrintStream("other.txt");
  90. 90
  91. 91 // 将字符串“hello PrintStream”+回车符,写入到输出流中
  92. 92 out.println("hello PrintStream");
  93. 93 // 将0x41写入到输出流中
  94. 94 // 0x41对应ASCII码的字母'A',也就是写入字符'A'
  95. 95 out.write(0x41);
  96. 96 // 将字符串"65"写入到输出流中。
  97. 97 // out.print(0x41); 等价于 out.write(String.valueOf(0x41));
  98. 98 out.print(0x41);
  99. 99 // 将字符'B'追加到输出流中
  100. 100 out.append('B');
  101. 101
  102. 102 // 将"CDE is 5" + 回车 写入到输出流中
  103. 103 String str = "CDE";
  104. 104 int num = 5;
  105. 105 out.printf("%s is %d\n", str, num);
  106. 106
  107. 107 out.close();
  108. 108 } catch (IOException e) {
  109. 109 e.printStackTrace();
  110. 110 }
  111. 111 }
  112. 112 }

运行上面的代码,会在源码所在目录生成两个文件“file.txt”和“other.txt”。
file.txt的内容如下:

  1. abcde

other.txt的内容如下:

  1. hello PrintStream
  2. A65BCDE is 5

java的PrintStream(打印输出流)详解(java_io)的更多相关文章

  1. java io系列16之 PrintStream(打印输出流)详解

    本章介绍PrintStream以及 它与DataOutputStream的区别.我们先对PrintStream有个大致认识,然后再深入学习它的源码,最后通过示例加深对它的了解. 转载请注明出处:htt ...

  2. Java中PrintStream(打印输出流)

    Java中PrintStream(打印输出流)   PrintStream 是打印输出流,它继承于FilterOutputStream. PrintStream 是用来装饰其它输出流.它能为其他输出流 ...

  3. Java I/O输入输出流详解

    一.文件的编码               开发时一定要注意项目默认的编码!!!!!!!!               文件操作的时候一定要记得关闭!!!!!!!!        ASCII:美国标准 ...

  4. java中的io系统详解 - ilibaba的专栏 - 博客频道 - CSDN.NET

    java中的io系统详解 - ilibaba的专栏 - 博客频道 - CSDN.NET 亲,“社区之星”已经一周岁了!      社区福利快来领取免费参加MDCC大会机会哦    Tag功能介绍—我们 ...

  5. Java网络编程和NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型

    Java网络编程与NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型 知识点 nio 下 I/O 阻塞与非阻塞实现 SocketChannel 介绍 I/O 多路复用的原理 事件选择器与 ...

  6. Java中的main()方法详解

    在Java中,main()方法是Java应用程序的入口方法,也就是说,程序在运行的时候,第一个执行的方法就是main()方法,这个方法和其他的方法有很大的不同,比如方法的名字必须是main,方法必须是 ...

  7. Java面试题04-final关键字详解

    Java面试题04-final关键字详解 本篇博客将会讨论java中final关键字的含义,以及final用在什么地方,感觉看书总会有一些模糊,而且解释的不是很清楚,在此做个总结,以备准备面试的时候查 ...

  8. Java I/O : Java中的进制详解

    作者:李强强 上一篇,泥瓦匠基础地讲了下Java I/O : Bit Operation 位运算.这一讲,泥瓦匠带你走进Java中的进制详解. 一.引子 在Java世界里,99%的工作都是处理这高层. ...

  9. Java网络编程和NIO详解开篇:Java网络编程基础

    Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为 ...

随机推荐

  1. 【Linux】centos7 添加脚本到/etc/rc.local文件里,实现开机自启

    Linux 设置开机自启动,添加命令到/etc/rc.d/rc.local,本文以设置tomcat自启动为例: 一:添加自启动命令 export JAVA_HOME=/usr/java/jdk1.8. ...

  2. elk大纲

    一.ELK功能概览 1.检索 2.数据可视化--实时监控(实时刷新) nginx 访问量 ip地区分布图(大数据) 3.zabbix 微信联动报警 4.大数据日志分析平台(基于hadoop) 二.ka ...

  3. CentOS下安装微软雅黑字体

    CentOS下安装微软雅黑字体   微软雅黑下载地址:http://download.csdn.net/detail/u012547633/9796219 1.先从你本机 C:\Windows\Fon ...

  4. 【Hadoop】二、HDFS文件读写流程

    (二)HDFS数据流   作为一个文件系统,文件的读和写是最基本的需求,这一部分我们来了解客户端是如何与HDFS进行交互的,也就是客户端与HDFS,以及构成HDFS的两类节点(namenode和dat ...

  5. [luogu3067 USACO12OPEN] 平衡的奶牛群

    传送门 Solution 折半搜索模板题 考虑枚举每个点在左集合和右集合或者不在集合中,然后排序合并即可 Code //By Menteur_Hxy #include <cmath> #i ...

  6. 运行/调试你的PHP代码

    前言 没有任何一名程序员可以一气呵成.完美无缺的在不用调试的情况下完成一个功能或模块.调试实际分很多种情况.本篇文章我分享下自己在实际开发工作中的经验,我个人理解,调试分三种,注意我所讲的是调试并非测 ...

  7. Bazinga HDU 5510 Bazinga(双指针)

    Bazinga HDU 5510 Bazinga(双指针) 题链 解法:对于串i来说,如果串i是不符合的,那么代表串i之前的字符串都是i的子串,那么我们求一个新的i(定义为ti),如果i是ti 的子串 ...

  8. BZOJ 2095 [POI2010]Bridges (最大流、欧拉回路)

    洛谷上有这题,但是输出方案缺SPJ..(而且我也懒得输出方案了) 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2095 题解: 首先判 ...

  9. 【Codeforces 242C】King's Path

    [链接] 我是链接,点我呀:) [题意] 让你找到(x0,y0)到(x1,y1)的一条最短路 走过的点必须在所给的n个横向路径上 [题解] 因为n条横向路径上的点最多不会超过10的5次方个,所以我们可 ...

  10. HDU 1249 三角形的分割

    可以将三角形的三条边一条一条加进图形中观察 假设添加第n个三角形 前n-1个三角形将区域划分为sum[n-1] 第n个三角形每条边最多能经过前n-1个三角形每条三角形的两条边 , 一条边切完增加了 2 ...