目录
一、charset字符集
1.字符的字节数
2.使用的Api
二、File类
1.构造方法
2.常用Api
3.递归
三、IO流
1.概述
2.IO的分类
3.字节流
(1)字节输出流【OutputStream】
(2)字节输⼊流【InputStream】
4.字符流
(1)字符输⼊流【Reader】
(2)字符输出流【Writer】
5.对象流
(1)作用
(2)用法
6.小结
一、charset字符集
1.字符的字节数
字符集: 支持中文 GBK UTF-8
英文和数字, 在所有的字符集中都可以正常显示, 只有一个字节
中文: UTF-8 1个字符 = 3个字节
GBK 1个字符 = 2个字节
java中的字符char: 2个字节 unicode编码
2.使用的Api
解码的api: new String(byte[] bs, String charsetName)
编码的api: byte[] getBytes(String charsetName)
乱码问题:
使用不同的方式来编码和解码
解决乱码:
原路返回
例:
public class demo1 {
public static void main(String[] args) throws UnsupportedEncodingException {
String str="java自己能大";
byte[] by=str.getBytes("UTF-8");
System.out.println(Arrays.toString(by));
String bystr1=new String(by,"ISO-8859-1");
System.out.println(bystr1);
by=bystr1.getBytes("ISO-8859-1");
System.out.println(Arrays.toString(by));
bystr1=new String(by,"UTF-8");
System.out.println(bystr1);
}
}
二、File类
1.构造方法
public File(String pathname):通过将给定的路径名字符串转换为抽象路径名来创建新的 File 实例。
public File(String parent, String child) :从⽗路径名字符串和⼦路径名字符串创建新的 File 实例。
public File(File parent, String child) :从⽗抽象路径名和⼦路径名字符串创建新的 File 实例。
2.常用Api
public String getAbsolutePath() :返回此File的绝对路径名字符串。
public String getPath() :将此File转换为路径名字符串。
public String getName() :返回由此File表示的⽂件或⽬录的名称。
public long length() :返回由此File表示的⽂件的⻓度。
public boolean exists() :此File表示的⽂件或⽬录是否实际存在。
public boolean isDirectory() :此File表示的是否为⽬录。
public boolean isFile() :此File表示的是否为⽂件。
File file=new File("file/s.txt");
System.out.println("⽂件绝对路径:" + file.getAbsolutePath());
System.out.println("⽂件构造路径:" + file.getPath());
System.out.println("⽂件名称:" + file.getName());
System.out.println("⽂件⻓度:" + file.length() + "字节");
System.out.println("文件是否存在:"+file.exists());
System.out.println("是否是文件:"+file.isFile());
System.out.println("是否是目录:"+file.isDirectory());
public boolean createNewFile() :当且仅当具有该名称的⽂件尚不存在时,创建⼀个新的空⽂
件。
public boolean mkdir() :创建由此File表示的⽬录。
public boolean mkdirs() :创建由此File表示的⽬录,包括任何必需但不存在的⽗⽬录。
boolean mkdir = m.mkdir();//创建单级目录
boolean mkdir2 = m2.mkdirs();//创建多级目录
System.out.println("创建目录:"+mkdir+mkdir2);
if(!exist){
Boolean creat=file.createNewFile();
System.out.println("创建文件:"+creat);
}
public boolean delete() :删除由此File表示的⽂件或⽬录。
public String[] list() :返回⼀个String数组,表示该File⽬录中的所有⼦⽂件或⽬录。
public File[] listFiles() :返回⼀个File数组,表示该File⽬录中的所有的⼦⽂件或⽬录。
File file=new File("day02/file/aa/bb");
File[] files = file.listFiles();
for(File f:files){
f.delete();
}
file.delete();
筛选指定后缀文件:
File file=new File("day02/file/aa");
File[] files = file.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
boolean file1 = file.isFile();
boolean java = file.getName().endsWith(".txt");
return file1 && java;
}
});
for(File f:files){
System.out.println(f.getName());
}
API中说明:
1.delete⽅法,如果此File表示⽬录,则⽬录必须为空才能删除。
2.调⽤listFiles⽅法的File对象,表示的必须是实际存在的⽬录,否则返回null,⽆法进⾏遍历
3.递归
递归:指在当前⽅法内调⽤⾃⼰的这种现象。
递归的条件:
1.递归公式(规律) 求n的阶乘 f(n) = f(n-1) * n
2.结束/终止的条件 n=1
3.递归方向: 往结束的条件
注意:递归不终止, 会造成栈溢出 StackOverError
常见的递归案例: 斐波那契数列 汉诺塔 二叉树
例:删除多级目录和文件
public static void main(String[] args) {
File file=new File("day02/file/aa/bb");
String[] strings= file.list();
deleteDir(file);
}
public static void deleteDir(File dir){
File[] files=dir.listFiles();
if(files!=null&&files.length>0){
for(File f:files){
if(f.isDirectory())
deleteDir(f);
else
f.delete();
}
}
dir.delete();
}
三、IO流
1.概述
Java中I/O操作主要是指使⽤ java.io 包下的内容,进⾏输⼊、输出操作。输⼊也叫做读取数据,输出也 叫做作写出数据。
2.IO的分类
根据数据的流向分为:输⼊流和输出流。
输⼊流 :把数据从 其他设备 上读取到 内存 中的流。
输出流 :把数据从 内存 中写出到 其他设备 上的流。
格局数据的类型分为:字节流和字符流。
字节流 :以字节为单位,读写数据的流。
输入: InputStream -> FileInputStream
输出: OutputStream -> FileOutputStream
字符流 :以字符为单位,读写数据的流。
输入: Reader
输出: Writer
3.字节流
(1)字节输出流【OutputStream】
构造⽅法
public FileOutputStream(File file) :创建⽂件输出流以写⼊由指定的 File对象表示的⽂件。
public FileOutputStream(String name) :创建⽂件输出流以指定的名称写⼊⽂件。
常用方法
public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
public void write(byte[] b) :将 b.length字节从指定的字节数组写⼊此输出流。
public void write(byte[] b, int off, int len) :从指定的字节数组写⼊ len 字节,从偏移
量 off 开始输出到此输出流。
public abstract void write(int b) :将指定的字节输出流。
File file=new File("day02/file/aa/out.txt");
// append-true, 打开文件, 并写入文件末尾 (追加)
FileOutputStream fos=new FileOutputStream(file,true);
fos.write(-25);
fos.write(-113);
fos.write(-83);
byte[] bs = {-25, -113, -83};
// 将指定字节数组的所有字节一起写入文件中
fos.write(bs);
byte[] bs1 = "天气太热了".getBytes();
// 将bs1字节中, 从off开始, 写len个字节
fos.write(bs1, 3, 9);
byte[] by={-24, -121, -86, -27, -73, -79};
fos.write(by,0,6);
fos.close();
(2)字节输⼊流【InputStream】
构造⽅法
FileInputStream(File file) :通过打开与实际⽂件的连接来创建⼀个 FileInputStream ,该⽂件
由⽂件系统中的 File对象 file命名。
FileInputStream(String name) :通过打开与实际⽂件的连接来创建⼀个 FileInputStream ,该⽂件由⽂件系统中的路径名 name命名。
常用方法
public void close() :关闭此输⼊流并释放与此流相关联的任何系统资源。
public abstract int read() :从输⼊流读取数据的下⼀个字节。
public int read(byte[] b) :从输⼊流中读取⼀些字节数,并将它们存储到字节数组 b中 。
// 如果文件不存在, 抛出 FileNotFoundException
File file = new File("dd/out.txt");
FileInputStream fis = new FileInputStream(file);
int i;
while ((i=fis.read())!=-1){
System.out.print(i+",");
}
byte[] bs = new byte[(int)(file.length())];
System.out.println("bs 的长度: " + bs.length);
// 读一些字节, 存入到 bs 数组中, 最多读20个字节
int len = fis.read(bs);
System.out.println(Arrays.toString(bs));
System.out.println("读出来的个数: " + len);
// 解码, 从bs数组的0位置开始, 一共解码 len 个字节
String str = new String(bs, 0, len, "UTF-8");
System.out.println("读出来的字节解码后: " + str);
字节流常用于复制文件
FileOutputStream fos=new FileOutputStream("day02/file/read-copy.png");
FileInputStream fis=new FileInputStream("day02/file/read.png");
byte[] bs=new byte[1024];
int i;
while ((i= fis.read(bs))!=-1){
fos.write(bs,0,i);
}
fos.close();
fis.close();
进阶:带缓冲区的复制文件(效率更高)
FileOutputStream fos=new FileOutputStream("day02/file/read-copy.png");
FileInputStream fis=new FileInputStream("day02/file/read.png");
//添加缓冲区
BufferedOutputStream bos=new BufferedOutputStream(fos);
BufferedInputStream bis=new BufferedInputStream(fis);
long start=System.currentTimeMillis();
byte[] bs=new byte[1024];
int i;
while ((i= bis.read())!=-1){
bos.write(bs,0,i);
}
long end=System.currentTimeMillis();
bis.close();
bos.close();
fos.close();
fis.close();
System.out.println("时间:"+(end-start));
4.字符流
(1)字符输⼊流【Reader】
构造方法
FileReader(File file) :创建⼀个新的 FileReader ,给定要读取的File对象。
FileReader(String fileName) :创建⼀个新的 FileReader ,给定要读取的⽂件的名称。
常用方法
public void close() :关闭此流并释放与此流相关联的任何系统资源。
public int read() :从输⼊流读取⼀个字符。
public int read(char[] cbuf) :从输⼊流中读取⼀些字符,并将它们存储到字符数组 cbuf 中。
FileReader reader=new FileReader("day02/file/out.txt");
int i= reader.read();
System.out.println("i:"+i);
System.out.println((char) i);
char[] chars=new char[20];
int len=reader.read(chars);//读出来的字符数
System.out.println("内容是:"+chars);
System.out.println(chars);
String str=new String(chars,0,len);
System.out.println(str);
(2)字符输出流【Writer】
构造方法
FileWriter(File file) :创建⼀个新的 FileWriter,给定要读取的File对象。
FileWriter(String fileName) :创建⼀个新的 FileWriter,给定要读取的⽂件的名称。
常用方法
void write(int c) :写⼊单个字符。
void write(char[] cbuf) :写⼊字符数组。
abstract void write(char[] cbuf, int off, int len) :写⼊字符数组的某⼀部分,off数组的开始索引,len写的字符个数。
void write(String str) :写⼊字符串。
void write(String str, int off, int len) :写⼊字符串的某⼀部分,off字符串的开始索引,len写的字符个数。
void flush() :刷新该流的缓冲。
void close() :关闭此流,但要先刷新它。
FileWriter writer=new FileWriter("day02/file/out.txt");
//自带缓冲区—>内存中
writer.write("好");
writer.write('h');
char[] chars={'h','e','n'};
writer.write(chars);
writer.write(chars,1,2);
String str="真好!";
writer.write(str);
writer.write(str,1,2);
writer.flush();
writer.close();//关闭流,先刷新
字符流常用于读写文件
例:按行读取文件(BufferedReader)
FileReader reader=new FileReader("day02/file/out.txt");
BufferedReader br=new BufferedReader(reader);
String str;
while ((str=br.readLine())!=null){
System.out.println(str);
}
br.close();
将数据打印到文件中(PrintWriter)
// PrintWriter 8个构造方法
// autoFlush -> true, 只有使用println方法写入的时候, 才会自动刷新缓冲区
public static void main(String[] args) throws IOException {
// 1.1直接传递一个文件名: 使用默认字符集, 清空原文件, 不会自动刷新缓冲区
PrintWriter pw1 = new PrintWriter("out.txt");
// 1.2传递一个文件名 + 字符集: 使用指定字符集, 清空原文件, 不会自动刷新缓冲区
PrintWriter pw2 = new PrintWriter("out.txt", "GBK");
// 2传递一个文件对象(或者 + 字符集): 效果同 1
// 3.1传递一个字节流: 使用默认字符集, 清空原文件, 不会自动刷新
FileOutputStream fos3 = new FileOutputStream("out.txt");
PrintWriter pw3 = new PrintWriter(fos3);
// 3.2传递一个字节流+自动刷新: 使用默认字符集, 清空原文件, 会自动刷新(println)
FileOutputStream fos4 = new FileOutputStream("out.txt");
PrintWriter pw4 = new PrintWriter(fos4, true);
// 3.3传递一个字节流: 使用默认字符集, 在原文件上追加
FileOutputStream fos5 = new FileOutputStream("out.txt", true);
PrintWriter pw5 = new PrintWriter(fos5, true);
// 4.传递一个字符流(或者 + 自动刷新): 效果同3
// 5.转换流(字符流Writer) OutputStreamWriter
FileOutputStream fos = new FileOutputStream("out.txt", true);
OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
PrintWriter pw = new PrintWriter(osw, true);
pw.println("你好, 今天吃了吗? 没吃呢还");
//pw.flush();
}
一个字符集是GBK的文件,使用 BufferedReader 一行一行读取出来, 并且打印到控制台
File f=new File("day02/file/aa/out.txt");
FileInputStream fis=new FileInputStream(f);
InputStreamReader isr=new InputStreamReader(fis,"GBK");
BufferedReader br=new BufferedReader(isr);
String str;
while ((str=br.readLine())!=null) {
System.out.println(str);
}
br.close();
5.对象流
(1)作用
文件里存放对象(属性 , 值)
(2)用法
新建一个Person类,接口Serializable表示可序列化的
public class Person implements Serializable {
public static final long serialVersionUID = 2l;//UID唯一
public String name;
public int age;
private transient char sex;//transient: 临时属性
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
将Person对象存入文件
Person p1=new Person("张三",18);
FileOutputStream fos=new FileOutputStream("day02/file/obj.txt");
ObjectOutputStream oos=new ObjectOutputStream(fos);
// 序列化
oos.writeObject(p1);
oos.close();
从文件中读取对象
FileInputStream fis=new FileInputStream("day02/file/obj.txt");
ObjectInputStream ois=new ObjectInputStream(fis);
// 反序列化
Person p1=(Person) ois.readObject();
System.out.println(p1);
ois.close();
6.小结
字节流的父类: InputStream / OutputStream
字符流的父类: Reader / Writer
字节流的普通子类: FileInputStream / FileOutputStream
字符流的普通子类: FileReader / FileWriter
带缓冲区的字节流: BufferedInputStream / BufferedOutputStream
带缓冲区的字符流: BufferedReader / PrintWriter(打印流)
转换流: OutputStreamWriter / InputStreamReader
对象流: ObjectInputStream ObjectOutputStream
readObject() writeObject()
transient: 临时属性, 不会写入到文件中
出现的异常:
NotSerializableException: 不是可序列化的, 需要添加可序列化接口
Serializable: 接口内容 无
InvalidClassException: 不兼容的类型, 需要添加版本号来固定版本
public static final long serialVersionUID=唯一



