Skip to content

Commit cebabe2

Browse files
committed
打印流
1 parent 19eeae3 commit cebabe2

File tree

4 files changed

+219
-69
lines changed

4 files changed

+219
-69
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,10 @@
175175
- [字符流:Reader和Writer的故事](docs/io/reader-writer.md)
176176
- [缓冲流:Java IO 的读写效率有了质的飞升](docs/io/buffer.md)
177177
- [转换流:Java 字节流和字符流的桥梁](docs/io/char-byte.md)
178-
- [Java序列化流,字节和对象之间的序列化和反序列化](docs/io/serialize.md)
179-
- [Java Serializable:明明就一个空的接口嘛](docs/io/Serializbale.md)
180-
- [招银面试官:说说Java transient关键字](docs/io/transient.md)
181-
- [Java打印流:PrintStream & PrintWriter](docs/io/print.md)
178+
- [打印流:PrintStream & PrintWriter](docs/io/print.md)
179+
- [序列流:字节和对象之间的序列化和反序列化](docs/io/serialize.md)
180+
- [Serializable:明明就一个空的接口嘛](docs/io/Serializbale.md)
181+
- [Java transient关键字](docs/io/transient.md)
182182

183183
## 异常处理
184184

docs/home.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,6 @@ head:
178178
- [详解 Java 中的优先级队列(PriorityQueue 附源码分析)](collection/PriorityQueue.md)
179179
- [Comparable和Comparator的区别](basic-extra-meal/comparable-omparator.md)
180180

181-
182181
### Java输入输出
183182

184183
- [Java IO 的分类](io/shangtou.md)
@@ -187,10 +186,10 @@ head:
187186
- [字符流:Reader和Writer的故事](io/reader-writer.md)
188187
- [缓冲流:Java IO 的读写效率有了质的飞升](io/buffer.md)
189188
- [转换流:Java 字节流和字符流的桥梁](io/char-byte.md)
190-
- [Java序列化流,字节和对象之间的序列化和反序列化](io/serialize.md)
191-
- [Java Serializable:明明就一个空的接口嘛](io/Serializbale.md)
192-
- [招银面试官:说说Java transient关键字](io/transient.md)
193-
- [Java打印流:PrintStream & PrintWriter](io/print.md)
189+
- [打印流:PrintStream & PrintWriter](io/print.md)
190+
- [序列流:字节和对象之间的序列化和反序列化](io/serialize.md)
191+
- [Serializable:明明就一个空的接口嘛](io/Serializbale.md)
192+
- [说说Java transient关键字](io/transient.md)
194193

195194

196195
### 异常处理

docs/io/print.md

Lines changed: 99 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
2-
title: Java打印流:PrintStream & PrintWriter
3-
shortTitle: Java打印流PrintStream
2+
title: 打印流:PrintStream & PrintWriter
3+
shortTitle: 打印流
44
category:
55
- Java核心
66
tag:
@@ -9,87 +9,126 @@ description: Java程序员进阶之路,小白的零基础Java教程,Java打
99
head:
1010
- - meta
1111
- name: keywords
12-
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Java IO,打印流,PrintStream,PrintWriter
12+
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Java IO,打印流,PrintStream,PrintWriter,java 打印流
13+
1314
---
1415

15-
## 何谓打印流
16+
# 7.7 打印流
17+
18+
在我的职业生涯中, `System.out.println()` 的使用频率恐怕不亚于 main 方法的使用频率。其中 `System.out` 返回的正是打印流 `PrintStream`
19+
20+
除此之外,还有它还有一个孪生兄弟,PrintWriter。PrintStream 是 OutputStream 的子类,PrintWriter 是 Writer 的子类,也就是说,一个[字节流](https://tobebetterjavaer.com/io/stream.html),一个是[字符流](https://tobebetterjavaer.com/io/reader-writer.html)
21+
22+
打印流具有以下几个特点:
23+
24+
* 可以自动进行数据类型转换:打印流可以将各种数据类型转换为字符串,并输出到指定的输出流中。
25+
* 可以自动进行换行操作:打印流可以在输出字符串的末尾自动添加换行符,方便输出多个字符串时的格式控制。
26+
* 可以输出到控制台或者文件中:打印流可以将数据输出到控制台或者文件中,方便调试和日志记录(尽管生产环境下更推荐使用 [Logback](https://tobebetterjavaer.com/gongju/logback.html)、ELK 等)。
27+
28+
PrintStream 类的常用方法包括:
29+
30+
- `print()`:输出一个对象的字符串表示形式。
31+
- `println()`:输出一个对象的字符串表示形式,并在末尾添加一个换行符。
32+
- `printf()`:使用指定的格式字符串和参数输出格式化的字符串。
33+
34+
来一个示例体验一下。
35+
36+
```java
37+
PrintStream ps = System.out;
38+
ps.println("沉默王二");
39+
ps.print("");
40+
ps.print("");
41+
ps.print("");
42+
ps.print("");
43+
ps.println();
44+
45+
ps.printf("姓名:%s,年龄:%d,成绩:%f", "沉默王二", 18, 99.9);
46+
```
47+
48+
在这个示例中,我们创建了一个 PrintStream 对象 ps,它输出到控制台。我们使用 ps 的 print 和 println 方法输出了一些字符串。
49+
50+
使用 printf 方法输出了一个格式化字符串,其中 %s、%d 和 %.2f 分别表示字符串、整数和浮点数的格式化输出。我们使用逗号分隔的参数列表指定了要输出的值。
1651

17-
平时我们在控制台打印输出,是调用`print`方法和`println`方法完成的,各位用了这么久的输出语句肯定没想过这两个方法都来自于`java.io.PrintStream`类吧,哈哈。该类能够方便地打印各种数据类型的值,是一种便捷的输出方式
52+
来详细说说 printf 方法哈
1853

19-
**打印流分类**
54+
```java
55+
public PrintStream printf(String format, Object... args);
56+
```
2057

21-
> 字节打印流PrintStream,字符打印流PrintWriter
58+
其中,format 参数是格式化字符串,args 参数是要输出的参数列表。格式化字符串包含了普通字符和转换说明符。普通字符是指除了转换说明符之外的字符,它们在输出时直接输出。转换说明符是由百分号(%)和一个或多个字符组成的,用于指定输出的格式和数据类型。
2259

23-
**打印流特点**
60+
下面是 Java 的常用转换说明符及对应的输出格式
2461

25-
> A:只操作目的地,不操作数据源
26-
>
27-
> B:可以操作任意类型的数据
28-
>
29-
> C:如果启用了自动刷新,在调用println()方法的时候,能够换行并刷新
30-
>
31-
> D:可以直接操作文件
62+
- `%s`:输出一个字符串。
63+
- `%d``%i`:输出一个十进制整数。
64+
- `%x``%X`:输出一个十六进制整数,`%x` 输出小写字母,`%X` 输出大写字母。
65+
- `%f``%F`:输出一个浮点数。
66+
- `%e``%E`:输出一个科学计数法表示的浮点数,`%e` 输出小写字母 e,`%E` 输出大写字母 E。
67+
- `%g``%G`:输出一个浮点数,自动选择 `%f``%e/%E` 格式输出。
68+
- `%c`:输出一个字符。
69+
- `%b`:输出一个布尔值。
70+
- `%h`:输出一个哈希码(16进制)。
71+
- `%n`:换行符。
3272

33-
这个时候有同学就要问了,哪些流可以直接操作文件呢?答案很简单,**如果该流的构造方法能够同时接收File和String类型的参数,一般都是可以直接操作文件的**
73+
除了转换说明符之外,Java 的 printf 方法还支持一些修饰符,用于指定输出的宽度、精度、对齐方式等。
3474

35-
PrintStream是OutputStream的子类,PrintWriter是Writer的子类,两者处于对等的位置上,所以它们的API是非常相似的。二者区别无非一个是字节打印流,一个是字符打印流。
75+
- 宽度修饰符:用数字指定输出的最小宽度,如果输出的数据不足指定宽度,则在左侧或右侧填充空格或零。
76+
- 精度修饰符:用点号(.)和数字指定浮点数或字符串的精度,对于浮点数,指定小数点后的位数,对于字符串,指定输出的字符数。
77+
- 对齐修饰符:用减号(-)或零号(0)指定输出的对齐方式,减号表示左对齐,零号表示右对齐并填充零。
3678

37-
## 字节输出打印流PrintStream复制文本文件
79+
下面是一些示例:
3880

3981
```java
40-
import java.io.BufferedReader;
41-
import java.io.FileReader;
42-
import java.io.IOException;
43-
import java.io.PrintStream;
44-
45-
public class PrintStreamDemo {
46-
public static void main(String[] args) throws IOException {
47-
BufferedReader br=new BufferedReader(new FileReader("copy.txt"));
48-
PrintStream ps=new PrintStream("printcopy.txt");
49-
String line;
50-
while((line=br.readLine())!=null) {
51-
ps.println(line);
52-
}
53-
br.close();
54-
ps.close();
55-
}
56-
}
82+
int num = 123;
83+
System.out.printf("%5d\n", num); // 输出 " 123"
84+
System.out.printf("%-5d\n", num); // 输出 "123 "
85+
System.out.printf("%05d\n", num); // 输出 "00123"
86+
87+
double pi = Math.PI;
88+
System.out.printf("%10.2f\n", pi); // 输出 " 3.14"
89+
System.out.printf("%-10.4f\n", pi); // 输出 "3.1416 "
90+
91+
String name = "沉默王二";
92+
System.out.printf("%10s\n", name); // 输出 " 沉默王二"
93+
System.out.printf("%-10s\n", name); // 输出 "沉默王二 "
5794
```
58-
5995

60-
## 字符输出打印流PrintWriter复制文本文件
96+
具体来说,
97+
98+
- 我们使用 `%5d` 来指定输出的整数占据 5 个字符的宽度,不足部分在左侧填充空格。
99+
- 使用 `%-5d` 来指定输出的整数占据 5 个字符的宽度,不足部分在右侧填充空格。
100+
- 使用 `%05d` 来指定输出的整数占据 5 个字符的宽度,不足部分在左侧填充 0。
101+
- 使用 `%10.2f` 来指定输出的浮点数占据 10 个字符的宽度,保留 2 位小数,不足部分在左侧填充空格。
102+
- 使用 `%-10.4f` 来指定输出的浮点数占据 10 个字符的宽度,保留 4 位小数,不足部分在右侧填充空格。
103+
- 使用 `%10s` 来指定输出的字符串占据 10 个字符的宽度,不足部分在左侧填充空格。
104+
- 使用 `%-10s` 来指定输出的字符串占据 10 个字符的宽度,不足部分在右侧填充空格。
105+
106+
接下来,我们给出一个 PrintWriter 的示例:
61107

62108
```java
63-
import java.io.BufferedReader;
64-
import java.io.FileReader;
65-
import java.io.FileWriter;
66-
import java.io.IOException;
67-
import java.io.PrintWriter;
68-
/**
69-
* 使用打印流复制文本文件
70-
*/
71-
public class PrintWriterDemo {
72-
public static void main(String[] args) throws IOException {
73-
BufferedReader br=new BufferedReader(new FileReader("aa.txt"));
74-
PrintWriter pw=new PrintWriter("printcopyaa.txt");
75-
String line;
76-
while((line=br.readLine())!=null) {
77-
pw.println(line);
78-
}
79-
br.close();
80-
pw.close();
81-
}
82-
}
109+
PrintWriter writer = new PrintWriter(new FileWriter("output.txt"));
110+
writer.println("沉默王二");
111+
writer.printf("他的年纪为 %d.\n", 18);
112+
writer.close();
83113
```
84114

85-
>参考链接:[https://www.cnblogs.com/yichunguo/p/11775270.html](https://www.cnblogs.com/yichunguo/p/11775270.html),整理:沉默王二
115+
首先,我们创建一个 PrintWriter 对象,它的构造函数接收一个 Writer 对象作为参数。在这里,我们使用 FileWriter 来创建一个输出文件流,并将其作为参数传递给 PrintWriter 的构造函数。然后,我们使用 PrintWriter 的 println 和 printf 方法来输出两行内容,其中 printf 方法可以接收格式化字符串。最后,我们调用 PrintWriter 的 close 方法来关闭输出流。
86116

117+
我们也可以不创建 FileWriter 对象,直接指定文件名。
118+
119+
```java
120+
PrintWriter pw = new PrintWriter("output.txt");
121+
pw.println("沉默王二");
122+
pw.printf("他的年纪为 %d.\n", 18);
123+
pw.close();
124+
```
125+
126+
好,关于打印流我们就说这么多,比较简单。至于 printf 的一些规则,用到的时候可以再查使用说明或者看 API 文档就可以了,记不住没关系。
87127

88128
---------
89129

90130
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
91131

92132
微信搜 **沉默王二** 或扫描下方二维码关注二哥的原创公众号沉默王二,回复 **111** 即可免费领取。
93133

94-
95-
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/gongzhonghao.png)
134+
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/gongzhonghao.png)
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
---
2+
title: 为什么魂斗罗只有 128KB 却可以实现那么长的剧情?
3+
shortTitle: 为什么魂斗罗只有 128KB 却可以实现那么长的剧情?
4+
description: 解密魂斗罗
5+
author: 皮皮关
6+
category:
7+
- 微信公众号
8+
---
9+
10+
大家好,我是小北。
11+
12+
经常看到有同学在抱怨现在的游戏、APP占用非常大的空间,基本都是 10G 起步。
13+
14+
在网上看到一个问题:
15+
16+
为什么魂斗罗只有 128KB 却可以实现那么长的剧情呢?
17+
18+
这篇文章将会给大家讲讲这里面的奥秘~
19+
20+
> 作者 l 皮皮关 原文链接:https://www.zhihu.com/question/50076174/answer/1101330430
21+
22+
# 正文
23+
24+
![](https://mmbiz.qpic.cn/mmbiz_png/VyxCxUCalFOLljnwCHH6xxZjCYBFuVPibrYeKHfTu3fTrZ16qvf1RR3icTCCIkG2yQX8fUBQGY59kxV62Uudm3wg/640?wx_fmt=png)
25+
26+
现代程序员 A 和 1980 年代游戏程序员 B 的对话:
27+
28+
A:为什么你用 128KB 能实现这么多画面、音乐、动画?
29+
30+
B:128KB 还不够么?其实为了表现力已经相当奢侈了,加了很多不重要的细节。
31+
32+
A:就说你们的音乐,这个音乐,我压到最低码率的 mp3,也得至少 1MB 吧。
33+
34+
B:你怎么压的?一首背景音乐怎么可能超过 1KB。
35+
36+
A:那你实现全屏卷轴,用了多少显存?
37+
38+
B:一共就只有 2KB 显存,多了也放不下啊。
39+
40+
A:……
41+
42+
# 我们对“数据量”无法直观认识
43+
44+
除非是专家,一般人根本无法估算到底多大算大,多小算小。
45+
46+
一般人对“数据量”并没什么概念。一篇 800 字的作文有多少数据量?按照 GBK 编码,约 1.6KB,按照 UTF-8 编码,则是 2.4KB。
47+
48+
只写了 1 个字的作文,按理来说 1 字节~3 字节就够了。但只写 1 个字的 word 文档,有 10956 字节,而由于硬盘格式化要求,再多占用 1332 字节
49+
50+
![](https://mmbiz.qpic.cn/mmbiz_png/VyxCxUCalFOLljnwCHH6xxZjCYBFuVPibjib7TiaJ7D8yZVoYQtE5YOYK4zicNEb1LeOfnthG9ITIDjeqvt0XeSEIQ/640?wx_fmt=png)
51+
52+
我就写了一个字,真的什么都没干
53+
54+
现实中常见的产品、流行的技术,实际上和时代背景密切相关。
55+
56+
当你抱着 15 寸笔记本还嫌小的时候,1990 年代初的家庭,可是一家人围着 14~18 寸的球面电视看的。把雪碧拿给古代人喝一口,估计他会齁得要死,必须喝点水压压惊。
57+
58+
![](https://mmbiz.qpic.cn/mmbiz_png/VyxCxUCalFOLljnwCHH6xxZjCYBFuVPibaT13fLPOQBenJhzkVcH6ndloenowq7g4ybjFEYchX02q9diaic4L5noQ/640?wx_fmt=png)
59+
60+
当物质基础变得十分丰富的时候,一定会产生无法避免的“浪费”,这种“浪费”会进一步改变人感受的阈值,对度量的估计都变得紊乱了。
61+
62+
# FC 时代的图形技术
63+
64+
由于早期的记忆芯片(ROM)非常贵,而且大容量磁盘的技术也不成熟,所以暂且不论硬件计算能力,仅仅是想增加游戏的总容量也非常困难。所以自然会使用符合当时水平的数据结构。
65+
66+
以红白机 FC 为例,它的分辨率为 256x240。分辨率不算低,但却只有 2KB 显存,而且还要实现全屏卷轴效果。
67+
68+
所以在 FC 设计之初,从硬件上就提供了充分利用显存的方法——使用 Tile(瓦片)。
69+
70+
对每一个场景来说,使用若干数量的瓦片,场景用有限的瓦片拼接即可。这种“二级”表示方法能极大节约存储量。
71+
72+
具体一些原理讲解可以看一些科普,比如这个:
73+
74+
https://www.bilibili.com/video/BV19J411e763
75+
76+
![](https://mmbiz.qpic.cn/mmbiz_png/VyxCxUCalFOLljnwCHH6xxZjCYBFuVPibQKaq5iaIOybIiakOQ5Yvg5ajwCmiaRG28olCBTcCXo8vBGy6mCicXgFkqw/640?wx_fmt=png)
77+
78+
# 音频容量和代码容量
79+
80+
现代音乐格式往往直接保存声道的波形,这种做法保真度高、通用性强,但很显然占用空间多,一首曲子的容量以千字节、兆字节计算。
81+
82+
而八位芯片时代的音频解决方案,关键是一颗专用芯片,例如 FC 用的理光 2A03:
83+
84+
![](https://mmbiz.qpic.cn/mmbiz_png/VyxCxUCalFOLljnwCHH6xxZjCYBFuVPibz6bS3COnoDjfLZKpevVdaUytmK4rI3iaibcoPp8p3PPEVNRj76zibRlCA/640?wx_fmt=png)
85+
86+
下:理光 2A03
87+
88+
音频芯片可以产生合成音效,能提供的音色可以在一定程度上配置,但非常有限。听听 FC 游戏的音乐可以体会到常用的音色几乎一样。
89+
90+
我觉得这个音频芯片最厉害的地方是可以同时播放几个音轨(但不能是和弦那种“同时”),《魂斗罗》、《沙罗曼蛇》、《忍者龙剑传》的殿堂级音乐,主要是靠多个音轨的交替配合实现的。
91+
92+
每个音符只要记录音色、频率和音高就足够了,音频芯片自然会识别出来。把音符按时间排列好就是“乐谱”了,可以简单理解为“简谱”。
93+
94+
![](https://mmbiz.qpic.cn/mmbiz_png/VyxCxUCalFOLljnwCHH6xxZjCYBFuVPibcqlz3SkQK6GQwC6LM980LMlbXtBYClq2LBzunWDgS1O6fgaibB9WXGQ/640?wx_fmt=png)
95+
96+
这种简谱需要的数据量十分有限,而且大部分游戏音乐都是循环播放,数据量更是小的可怜。
97+
98+
## 代码也是类似的
99+
100+
FC 时代的游戏,没有所谓的“引擎层”,或者说引擎层就是“硬件层”。任天堂的主机完全是为游戏而设计的,瓦片、调色板、音乐、音效等基本功能已经预先考虑到了,这样一来就节约了大量底层代码。
101+
102+
程序员要仔细研究文档,在硬件框架下思考问题,比如如何显示图片、如何卷动屏幕等等;而且还要非常熟悉硬件底层和汇编,不要浪费代码空间。
103+
104+
**一来二去,代码也能写的非常小。**
105+
106+
总的来说,128KB 的游戏大作,在 30 年前稀松平常,放到现在简直就是黑科技。
107+
108+
![](https://mmbiz.qpic.cn/mmbiz_png/VyxCxUCalFOLljnwCHH6xxZjCYBFuVPibqNmTWupthfqZhTfxMiavUZ1YvtoUTibBvKnrBuYF7Wx00qKibZlqOP63A/640?wx_fmt=png)
109+
110+
科技的剧烈变革带来技术指标非线性的变化,让我们的记忆和直觉彻底落伍 :)
111+
112+
>参考链接:[https://mp.weixin.qq.com/s/WpwYP88OHQROh_TJnNcz-Q](https://mp.weixin.qq.com/s/WpwYP88OHQROh_TJnNcz-Q),出处:编程指北,整理:沉默王二

0 commit comments

Comments
 (0)