普通文件可能是二进制文件可能是文本文件
输入:流式,水箱代表文件,流出来的水是数据。
1.InputStream(抽象类)(输入部分)
有俩个接口Closeable,Autocloseable可以关闭,就是把水龙头打开或者关闭
常用的方法:
abstract int read() //EOS,当值为1时说明流的最终端被读走了,也就是,文件里什么都没了。 一次一滴
int read(byte[] b) //一次一桶,byte[]b就是准备好的水桶(在内存中开辟好一块空间,从输入设备中把数据读到我内存的这个空间)
int read(byte[] b,int off,int len) //倒数俩个返回值<=b.length, -1才代表数据全部读完了,0不代表
接口的实现类
FileInputStream //从文件中往出读
SocketInputStream //从Socket往出读
这几行一共13个字节/r/n在第一行隐藏,意思是,回车
再回车一次,加俩个15个字节
代码示例
1.1文件读取的方法
当前是在io下
这里是相对路径,可以直接写hello.txt或者上面的这种,都是可以的
上面的一行,也可以写为
File file =new File("hello.txt);
FileInputStream is2 =new FeilInputStream(file);
一般写图片里面的就可以
然后我们知道文件有13个字节的数组,我们就用is.read(数组)
默认抛出的异常,是FileNotFoundException,路径/文件不存在
文件中49就是1的unicode编码
13 /r
10 /n
hello 就是 72 101 108 108 111
文件都被读完了,再读就是-1;
数组被改为10了之后,前面的按桶读,会变成10个字节,剩下llo没读
再读一次是按滴读的,就是读 l 也就是108
写成这样就不用写close了,会自动给我关掉
不知道数据源有多少数据的情况下,怎么确保把所有数据全部读完?
就是从里面读出来-1就代表结束掉了
可以写为
while(true){
int b =is.read();
if(b==-1){
break;
}
//加工b数据
}
用is.read(byte[] b)效果一样,下面会打印俩次,第一次10个,第二次3个
写为5,就是读三次。一般来说,读硬盘的频次越少越好,所以,容量写大一点(空间换时间)
一般为1024,或者1024的倍数,读一次即可
换中文读取:
原理上下面是4个字节,但是实际是12个字节
原因:UTF-8变长编码,意思是每个字符占用的字节长度是不相等的
数字、英文占1个字节
中文绝大多数占三个字节
emoji占4个字节,就是平常用的小表情
但是把这些查出来的数字还得自己查表对应出来,
用JDK直接得到查表得四个字
我们用的System.in就是InputStream类型
所以说,我们的new Scanner(InputStream类型 is,"utf-8")只要传入这个类型并把我们知道的字符集编码传入即可(我们平常看到的乱码就是以为的字符集和原本的字符集对不上)
而我们可以不改GBK,实现不乱码,就是把文件的utf-8改为GBK
1.2输入部分的其他一些
Reader类
Reader 地位和InputStream类似,做的是字符的处理
BufferedReader
reader.readLine() = scanner.nextLine();
2.OutputStream
最常见的实现类:FileOutputStream //向某一个文件中输入
2.1让中文写入正确
System.out 是PrintStream类型
练习,实现小程序
1.文本替换工具,“你好”(文件1)->“我好”(文件2)
思路:读、换、写
2.文件的复制(任意类型的文件都可以)一颗树的节点的复制
思路:IntputStream+OutputStream
也可以通过这个实现简单的文件夹的复制。
3.文件夹的复制(一颗树的复制)
思路:遍历文件夹中的每一个节点
第一行我要复制的目录的完整绝对路径
第二行源的开始复制的位置
第三行目标的开始复制的位置
所以相对路径就是目标开始位置+从绝对路径中截取源开始位置之后的目录
import java.io.File; import java.io.IOException; public class CopyDirectory { //源地址 static String source = "D:\\课程\\2022-05-08-Java19-22班-线程总结"; //目标地址 static String dest = "D:\\课程\\2022-05-09-Java19班-IO\\目标"; public static void main(String[] args) throws IOException { File srcFile = new File(source); //看源地址是不是目录 if (!srcFile.isDirectory()) { System.out.println("源不是目录"); return; } //看目标地址是否存在,如果存在则停止复制,防止把原来的目录删掉 File destFile = new File(dest); if (destFile.exists()) { System.out.println("目标路径已经存在"); return; } //递归复制的过程 traversal(srcFile, destFile); } private static void traversal(File dir, File destFile) throws IOException { //得到dir下所有的文件 File[] files = dir.listFiles(); if (files == null) { return; } for (File file : files) { //如果文件是个目录 if (file.isDirectory()) { //如何得到相对路径,本质上是在做字符串处理的工作 String path1 = file.getCanonicalPath(); //从源位置开始截取地址, String relative = path1.substring(source.length()); String path2 = dest + relative; File file2 = new File(path2); file2.mkdirs(); traversal(file, destFile); } else if (file.isFile()) { } } } }
剪切粘贴时间复杂度为O(1)
复制粘贴时间复杂度为O(n),因为有遍历的过程
课后代码:新建maven工程
字符图 像素->灰度->根据不同灰度替换
windows上面的换行\r\n
Linux上是\n
\r回到行首不换行
\n回到下一行
没听懂