io
读取和写出 in+out
File
文件和目录路径名。描述文件的对象。
File file = new File(path);
通过路径来创建文件对象。
createNewFile();
不存在时创建新文件
File也可以作为路径。dir.mkdir()
不存在时创建文件夹。
- 构造方法的第二种形式:父目录
new File(c://haha,b.txt);
- 删除:
o.delete()
listFiles()
获取所有文件,返回数组- 分隔路径,适配不同系统
File.pathSeparator
路径分隔符File.separator
名称分隔符
如何遍历一个文件夹下的所有文件
//File file = new File(pathname:"e:\\");
//File[] files = e.listFile();//得到这一层的文件
public static void listFiles(File[] files){
//传入文件数组
if(files!=null&&files.length>0){
//找到avi文件
for(File file:files){
if(file.isFile()){
//如果是文件
if(file.getName().endsWith(".avi")){
//找到需要的avi文件
System.out.println(file.getAbsolutePath());//打印绝对路径
//找大于200MB的文件
if(file.length()>200*1024*1024){
file.delete();
}
}else{
//不是文件则是文件夹
File[] files2 = file.listFiles();
//递归调用自己
listFiles(files2);
}
}
}
可以通过这样的程序来清理垃圾文件。
文件过滤器
//传入文件
public static void listFiles(File file){
//1. 创建过滤器 描述规则
FileFilter filter = new AVIFileFilter();
//2. 通过文件获取子文件夹
File[] files = file.listFiles();
//3. 避免空指针异常
if(files!=null&&files.length>0)
for...
}
static class AVIFileFilter implements FileFilter{
//描述规则
@Override
public boolean accept(File pathname){
if(pathname.getName().endsWith(".avi")||pathname.isDirectory());
return true;
return false;
}
}
}
更优的代码:匿名内部类
//因为过滤器只需要创建并使用一次
File[] files = file.listfiles(new FileFilter(){
@Override
public boolean accept(File pathname){
if(pathname.getName().endsWith(".avi")||pathname.isDirectory()){
return true;
}
return false;
}
});
相对路径和绝对路径
相对路径是相对项目的
IO流
数据传输看成是流动,按照流动的方向分为输入输出。
- 输入流输出流
- 数据类型:字节流(上传下载)字符流(文字乱码问题)
字节流
- 输入流顶级父类:
InputStream
输出流顶级父类:OutputStream
一切皆字节:计算机中的任何数据都是以二进制形式存储,传输时也是以二进制形式存储。任何流在传输时,底层都是二进制。
流的一些重要方法
close()
使用完毕后关闭流。如果读取完又不释放资源,关不掉,删不掉。flush()
刷新输出流,将缓冲的字节输出。- write 重载
- write(byte[] b) 从指定字节数组写入到输出流
- write(byte[] b, int off, int len) 从偏移量off开始的字节数组len字节写入到输出流
- write(int b) 指定字节 写入的是b的8个低位,24个高位忽略(int 4字节=32bit 1字节=8bit 最大11111111=255)
FileOutputStream向文件输出流
构造方法:
- File file写入的文件
- File file boolean append 追加还是覆盖?
FileOutputStream fos = new FileOutputStream("c://a.txt");
//一般用字符流写
byte[] bytes = "ABCDEF".getBytes();//变成字节数组成为65 66 67 68 69
fos.write(bytes, off:1, len:2);//从1下标开始写,写2个;
fos.close();//记得关闭
FileInputStream
InputStream下的子类。构造方法:
- File 对象
- String name路径名
//读取一个字节的方法
FileInputStream fis = new FileInputStream("c://a.txt");
//byte b = fis.read();//报错 返回的是int
byte b = (byte)fis.read();
//if(b==-1) break;//循环打印时结束
//小写的a是97 (char)b转成字符再打印
- read(byte[] b, int off, int len)读取一组字节。
注意如果建立byte[10],每次读10个,但每次不会自动清空,所以如果最后不足10个,它只会覆盖前几个,后几个没变。
输出时:len = fis.read(bytes); 打印new String(bytes, offset:0,len)
每次读取时获取长度。
一次读一组会更快。
字符流&文件利用异或字节加解密
- 输入流顶级父类:
Reader
输出流顶级父类:Writer
//加密存储的新文件 mi-a.png
File newFile = new file(oldFile.getParentFile(), "mi-"+oldFile.getName());
FileInputStream fis = new FileInputStream(oldFile);
FileOutputStream fos = new FileOutputStream(newFile);
while(true){
int b = fis.read();
if(b == -1){
break;
}
fos.write(b^=8);//如果知道密钥就可以解密
加密后的文件打不开。
计算机硬件组成
- 计算机中存储的文件都是二进制
- 硬件组成:硬盘 显卡 CPU 内存(装在主板上)
- 硬盘是磁盘,盘上有很多小点,给它加上磁。盘有凹凸不平的地方。凸起就是磁化,可以消除,这就是1。凹进去就是0。
- 机械硬盘好处,长时间存储。耐高温低温
- 固态硬盘存取快,不耐高温,时间长了也会丢失。读写速度超级快,NVME协议?一秒3G
- 内存 读写1s30g、60g。速度快,但是断电就没了。比如游戏里进入地图,地图资源放到内存里。
- 显卡 图形处理器,解析图像。计算每秒要变化的东西。专门进行浮点运算。结构简单,关注吞吐量。
- CPU 中央处理器,解析指令
- 显示器,1920发光体,里面有红绿蓝来控制显示的颜色。
- 带鱼屏 写代码不需要换行,也可以分屏
- 可旋转屏幕
字符编码
- ASCII码让计算机支持文字显示
- 创建自己语言的编码表,都兼容ASCII码表
- 英文是不会乱骂的
Unicode编码(UTF-8)
可变长度字符编码
字节流读取文件出现乱码问题
unicode是动态编码表,长度不定。如果设置new byte[10],可能一个字分为两部分两次被读取,就成了乱码。
字符流是按字符来读取的。
字符输入流
写入的单位是字符。构造方法:
FileWriter fw = new FileWriter("c://b.txt",append:true);//追加
- 有append方法
- 如果
fw2 = (FileWriter) fw.append();
那么fw==fw2
字符输出流
FileReader fr = new FileReader("b.txt");
int c = fr.read();
System.out.println((char)c);
//或者是输入到数组里
char[] chars = new char[100];
fr.read(chars);
String text = new String(chars,0,len);
字符和字节输出时不同
- 字符输出,但是计算机里存储的都是字节。如果有一个字符3个字节,那么会读满3个字节组织成文字输出,否则缓存起来。
- 写完之后只有关闭(或flush())输入流才会刷新,刷新之后才有文字显示
- 不刷新,文件内容都在内存里,没有输出的。
字节转换字符流
网上获取的都是字节,需要进行转换
//输入流的转换
FileInputStream ifs = new FileInputStream("c://a.txt");
//字节输入流转换为字符流(装饰者模式)
//要转换的字节流 fis 指定编码名称
InputStreamReader isr = new InputStreamReader(fis,"gbk");
while(true){
int c = isr.read();
if(c==-1){
break;
}
}
//输出流的转换
FileOutputStream fos = new FileOutputStream("");
字符输出 打印流
也可以用于转换字符流(原来用的是OutputStreamWriter)
PrintStream ps = new PrintStream("c://c.txt");
PrintWriter pw = new PrintWriter("c://c.txt");
记得要flush()
缓存读取流
将字符输入流转换为带有缓存,可以一次读取一行的缓存字符读取流
BufferedReader br = new BufferedReader(new FileReader("c://c.txt"));
String line = br.readLine();//按行读,结尾返回null
打印异常日志
try{
String s = null;
s.toString();
}catch(Exception e){
//传参传入一个打印流
PrintWriter pw = new PrintWriter("c://c.txt",true);
//打印日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
pw.println(sdf.format(new Date()));
e.printStackTrace(pw);
pw.close();
Properties
是HashTable的子类。跟Map集合一样,所以存键值对。但是扩展的部分跟IO有关系。
public static void main(String[] args) throws FileNotFoundException {
//.properties文件 配置文件格式
Properties ppt = new Properties();
//传入字符流或字节流
Reader r = new FileReader("");
ppt.load(r);//加载
//存储
FileWriter fw = new FileWriter("c://book.properties");
ppt.store(fw,comments:"存储的图书");//存入 注意中文会自动转成unicode码
//输出:ppt.get("name"); ppt.get("info");
//getProperty也可以获取
}
序列化与反序列化(面试考过)
能不能把对象存到文件里?
/*序列化,输出流*/
Book b = new Book("xx","ss");
//会报错NotSerializableException不让序列化,需要实现接口(会判断instanceof)
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(""));
oos.writeObject(b);
oos.clos();
/*反序列化,输入流*/
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(""));
Object o = ois.readObject();
//没有提供抽象方法只是个标记
static class Book implements Serializable{
private String name;
private String info;
...
toString(){}
}
总结:
- 序列化:对象->文件里的内容
- 反序列化:文件里的内容->对象
try-with-resources
JDK1.7出现
try(FileReader fr = new FileReader("")){
int c = fr.read();
} catch (IOException e){
e.printStackTrace();
}/**自动执行
finally{
try{
fr.close();
}catch(Exception e){
e.printStackTrace();
}
*/
但如果是传进来的fr 关不掉。
JDK1.9时
FireReader fr = new FileReader("");
PrintWriter pw = ....
//结束时必然调用对象的close()
try(fr;pw){
//读取
}catch(Exception e){
e.printStackTrace();
}