java基础(6) IO[下] 线程(补充) XML Servlet

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    try (InputStream input = new FileInputStream(f);
            OutputStream output = new FileOutputStream(t)) {
        int fLenght = (int) f.length();

        byte[] data = new byte[fLenght];
        System.out.println("文件长度为" + fLenght);
        int n;
        while ((n = input.read(data)) != -1) {
         
             output.write(data);
        }
       
    }

}

##### Filter模式(或者装饰器模式:Decorator)


当我们需要给一个“基础”InputStream附加各种功能时,我们先确定这个能提供数据源的InputStream,因为我们需要的数据总得来自某个地方,例如,FileInputStream,数据来源自文件:



InputStream file = new FileInputStream(“test.gz”)


我们希望FileInputStream能提供缓冲的功能来提高读取的效率,因此我们用BufferedInputStream包装这个InputStream,得到的包装类型是BufferedInputStream,但它仍然被视为一个InputStream:



InputStream buffered = new BufferedInputStream(file);


最后,如果这个文件已经被gzip压缩,我们可以封装一个`GZIPInputStream`,



InputStream gzip = new GZIPInputStream(buffered);


无论我们封装多少次,得到的对象始终是InputStream,我们直接用InputStream来引用它,就可以正常读取  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/65fe2e2560a540eeb4d0a24bc2396f3c.png)  
 上述这种通过一个“基础”组件再叠加各种“附加”功能组件的模式,称之为`Filter模式(或者装饰器模式:Decorator)`![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c4a82b2043cf41fa90eed86fe3ba63b4.png)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/04eb3e722766406ca936a1e511ad986c.png)


##### 操作Zip


ZipInputStream是一种FilterInputStream,他直接读取zip包的内容。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ed91fb2107cf4eb394efb642af8082c6.png)


读取  
 创建一个 ZipInputStream,循环调用getNextEntry(),直到返回null,表示zip流结束  
 getNextEntry返回一个zipEntry,一个ZipEntry表示一个压缩文件或目录,如果是压缩文件,我们就用read()方法不断读取,直到返回-1



try (ZipInputStream zip = new ZipInputStream(new FileInputStream(…))) {
ZipEntry entry = null;
while ((entry = zip.getNextEntry()) != null) {
String name = entry.getName();
if (!entry.isDirectory()) {
int n;
while ((n = zip.read()) != -1) {

}
}
}
}


###### 写入zip包



try (ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(…))) {
File[] files = …
for (File file : files) {
zip.putNextEntry(new ZipEntry(file.getName()));
zip.write(Files.readAllBytes(file.toPath()));
zip.closeEntry();
}
}


##### 序列化


序列化是指把一个Java对象变成二进制内容,本质上就是一个byte[]数组。  
 为什么需要序列化,因为通过byte[]可以保存到文件,也可以通过网络发送出去。  
 顾名思义反序列化就是将byte[]数组转位java对象。


###### java对象序列化


要实现序列化,就要实现java.io.Serializ

[video(video-8PGqMbZO-1716354551447)(type-bilibili)(url-https://player.bilibili.com/player.html?aid=1804892953)(image-https://img-blog.csdnimg.cn/img_convert/d03a705143646f4f3f6ea879d59b2788.png)(title-必看视频!获取2024年最新Java开发全套学习资料 备注Java)]

able接口,而Serializable接口没有定义任何方法和属性,



public interface Serializable {
}


它是一个空接口。我们把这样的空接口称为“标记接口”(Marker Interface),实现了标记接口的类仅仅是给自身贴了个“标记”,并没有增加任何方法。


借助ObjectOutputStream,他负责将数据对象写入字节流



public class Main {
public static void main(String[] args) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try (ObjectOutputStream output = new ObjectOutputStream(buffer)) {
// 写入int:
output.writeInt(12345);
// 写入String:
output.writeUTF(“Hello”);
// 写入Object:
output.writeObject(Double.valueOf(123.456));
}
System.out.println(Arrays.toString(buffer.toByteArray()));
}
}


打印的buffer是一个byte数组


###### 反序列化



try (ObjectInputStream input = new ObjectInputStream(…)) {
int n = input.readInt();
String s = input.readUTF();
Double d = (Double) input.readObject();
}


反序列化时,由JVM直接构造出Java对象,不调用构造方法,构造方法内部的代码,在反序列化时根本不可能执行。


##### 字符流 Reader


Reader是IO提供的另一个输入流接口,跟InputStream区别是,InputStream是以字节流为准,单位是byte,而Reader是一个字符流,单位是char。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/5fa868f0dc504173b4971d0c1e957450.png)  
 这个方法读取字符流的下一个字符,并返回字符表示的int(也就是可以用char来转换。),范围是0~65535(char表示范围,像InputStream的byte只能是0-255)。如果已读到末尾,返回-1。


###### FileReader


FileReader是Reader的子类,类似于FileInputStream于InputStream的关系。



// Java8不支持UTF_8
try (Reader reader = new FileReader(“./test.txt”, StandardCharsets.UTF_8)) {
int n;
while ((n = reader.read()) != -1) {
System.out.println((char) n);
}
}


也支持缓冲区读取



try (Reader reader = new FileReader(“./test.txt”)) {
char[] buffer = new char[5];
int n;
// n返回读取的char数
while ((n = reader.read(buffer)) != -1) {
System.out.println(buffer);
}
}


打印结果



hello
worl
d.中文l


###### CharArrayReader


CharArrayReader可以在内存中模拟一个Reader,它的作用实际上是把一个char[]数组变成一个Reader,这和ByteArrayInputStream非常类似:



try (Reader reader = new CharArrayReader(“Hello”.toCharArray())) {
}


###### StringReader


直接把String作为数据源。



try (Reader reader = new StringReader(“Hello”)) {
}


###### Reader和InputStream


普通的Reader实际上是基于InputStream构造的,因为Reader需要从InputStream中读入字节流(byte),然后,根据编码设置,再转换为char就可以实现字符流。如果我们查看FileReader的源码,它在内部实际上持有一个FileInputStream;


InputStreamReader可以把任务InputStream转位Reader



// 持有InputStream:
InputStream input = new FileInputStream(“src/readme.txt”);
// 变换为Reader:
Reader reader = new InputStreamReader(input, “UTF-8”);


##### Writer


Reader是带编码转换器的InputStream,它把byte转换为char,而Writer就是带编码转换器的OutputStream,它把char转换为byte并输出(把char转位byte然后写进去)。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/968c4e947b004059828358d202fb5b43.png)  
 Writer是所有字符输出流的超类,它提供的方法主要有:


* 写入一个字符(0~65535):void write(int c);
* 写入字符数组的所有字符:void write(char[] c);
* 写入String表示的所有字符:void write(String s)。


###### FileWirter


跟FileReader类似



    try (Reader reader = new FileReader("./test.txt"); Writer writer = new FileWriter("./test2.txt")) {
        char[] buffer = new char[5];
        int n;
        while ((n = reader.read(buffer)) != -1) {
            System.out.println("正在写入数据" + buffer);
            writer.write(buffer);
        }
        System.out.println("写入成功");
    }

###### CharArrayWriter


CharArrayWriter可以在内存中创建一个Writer,它的作用实际上是构造一个缓冲区,可以写入char,最后得到写入的char[]数组,这和ByteArrayOutputStream非常类似:



try (CharArrayWriter writer = new CharArrayWriter()) {
writer.write(65);
writer.write(66);
writer.write(67);
char[] data = writer.toCharArray(); // { ‘A’, ‘B’, ‘C’ }
}


内存中创建一个Writer,模拟写入。


###### StringWriter


StringWriter也是一个基于内存的Writer,它和CharArrayWriter类似。实际上,StringWriter在内部维护了一个StringBuffer,并对外提供了Writer接口。


###### OutputStreamWriter


与InputStreamReader相似。OutputStreamWriter可以讲OutputStream转位Writer



try (Writer writer = new OutputStreamWriter(new FileOutputStream(“readme.txt”), “UTF-8”)) {
// TODO:
}


###### 小结


* inputStream用户读取文件的字节流,单位是byte,read方法返回字节的int表示(0-255)
* Reader基于InputStream封装,他是以char为单位的字符流,read方法返回char的int表示,可以用(char) n来转换返回的数据。
* outputStream用户用来写入的字节流,单位是byte。
* Writer是基于outputStream封装的字符流,单位是char。
* InputStream: FileInputStream. ByteArrayInputStream
* outStream: FIleOutputStream byteArrayOutputStream
* Reader: FIleReader CharByteReader StringReader InputStreamReader(InputStream->Reader)
* Writer: FileWriter charByteWriter StringWriter OutputStreamWriter(OutputStream->Writer)


##### PrintStream和PrintWriter


`PrintStream是一种FilterOutputStream,它在OutputStream的接口上,额外提供了一些写入各种数据类型的方法:`


* 写入int:print(int)
* 写入boolean:print(boolean)
* 写入String:print(String)
* 写入Object:print(Object),实际上相当于print(object.toString())


…  
 以及对应的一组println()方法,它会自动加上换行符。  
 看着很像System.out.xxx


事实上`System.out.println()`实际上就是使用`PrintStream`打印各种数据。其中,`System.out`是系统默认提供的`PrintStream`


PrintStream和OutputStream相比,除了添加了一组print()/println()方法,可以打印各种数据类型,比较方便外,它还有一个额外的优点,就是不会抛出IOException,这样我们在编写代码的时候,就不必捕获IOException。


###### 有PirntStream就有PrintWriter,


PrintStream最终输出的总是byte数据,而PrintWriter则是扩展了Writer接口,它的print()/println()方法最终输出的是char数据。



public class Main {
public static void main(String[] args) {
StringWriter buffer = new StringWriter();
try (PrintWriter pw = new PrintWriter(buffer)) {
pw.println(“Hello”);
pw.println(12345);
pw.println(true);
}
System.out.println(buffer.toString());
}
}


小结  
 `PrintStream是一种能接收各种数据类型的输出,打印数据时比较方便:`


* System.out是标准输出;
* System.err是标准错误输出。


`PrintWriter是基于Writer的输出。`


##### Files


虽然Files是java.nio包里面的类,但他俩封装了很多读写文件的简单方法,极大的方便了我们读写文件。



byte[] data = Files.readAllBytes(Path.of(“/path/to/file.txt”));
// 默认使用UTF-8编码读取:
String content1 = Files.readString(Path.of(“/path/to/file.txt”));
// 可指定编码:
String content2 = Files.readString(Path.of(“/path”, “to”, “file.txt”), StandardCharsets.ISO_8859_1);
// 按行读取并返回每行内容:
List lines = Files.readAllLines(Path.of(“/path/to/file.txt”));


Files.readString是java11后支持的


###### 写入文件



// 写入二进制文件:
byte[] data = …
Files.write(Path.of(“/path/to/file.txt”), data);
// 写入文本并指定编码:
Files.writeString(Path.of(“/path/to/file.txt”), “文本内容…”, StandardCharsets.ISO_8859_1);
// 按行写入文本:
List lines = …
Files.write(Path.of(“/path/to/file.txt”), lines);


Files工具类还有copy()、delete()、exists()、move()等快捷方法操作文件和目录。



> 
> Files提供的读写方法,受内存限制,只能读写小文件,例如配置文件等,不可一次读入几个G的大文件。读写大型文件仍然要使用文件流,每次只读写一部分文件内容。
> 
> 
> 


# 总结:心得体会

既然选择这个行业,选择了做一个程序员,也就明白只有不断学习,积累实战经验才有资格往上走,拿高薪,为自己,为父母,为以后的家能有一定的经济保障。

学习时间都是自己挤出来的,短时间或许很难看到效果,一旦坚持下来了,必然会有所改变。不如好好想想自己为什么想进入这个行业,给自己内心一个答案。

面试大厂,最重要的就是夯实的基础,不然面试官随便一问你就凉了;其次会问一些技术原理,还会看你对知识掌握的广度,最重要的还是你的思路,这是面试官比较看重的。

最后,上面这些大厂面试真题都是非常好的学习资料,通过这些面试真题能够看看自己对技术知识掌握的大概情况,从而能够给自己定一个学习方向。包括上面分享到的学习指南,你都可以从学习指南里理顺学习路线,避免低效学习。

**大厂Java架构核心笔记(适合中高级程序员阅读):**

![](https://img-blog.csdnimg.cn/img_convert/c356fb3482fe2ede285d8d6146b46700.webp?x-oss-process=image/format,png)

的大文件。读写大型文件仍然要使用文件流,每次只读写一部分文件内容。
> 
> 
> 


# 总结:心得体会

既然选择这个行业,选择了做一个程序员,也就明白只有不断学习,积累实战经验才有资格往上走,拿高薪,为自己,为父母,为以后的家能有一定的经济保障。

学习时间都是自己挤出来的,短时间或许很难看到效果,一旦坚持下来了,必然会有所改变。不如好好想想自己为什么想进入这个行业,给自己内心一个答案。

面试大厂,最重要的就是夯实的基础,不然面试官随便一问你就凉了;其次会问一些技术原理,还会看你对知识掌握的广度,最重要的还是你的思路,这是面试官比较看重的。

最后,上面这些大厂面试真题都是非常好的学习资料,通过这些面试真题能够看看自己对技术知识掌握的大概情况,从而能够给自己定一个学习方向。包括上面分享到的学习指南,你都可以从学习指南里理顺学习路线,避免低效学习。

**大厂Java架构核心笔记(适合中高级程序员阅读):**

[外链图片转存中...(img-JWZJ1dGS-1716456340041)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值