IO流
字节流
FileOutputStream(内含编码解码)
FileOutputStream f = new FileOutputStream("D:\\JAVA\\a.txt");//字节输出流,自动创建文件
f.write(97);//将会按ASCII转化
f.write("\n".getBytes());//三种方式换行
f.write(98);
f.write("\r".getBytes());
f.write(99);
f.write("\r\n".getBytes());//windows默认\r\n
//可以通过.getBytes("GBK")或.getBytes("UTF-8")来指定编码方式
//汉字在GBK中占两个字节,在UTF-8中占3个
//当然,编码方式要和解码方式相同
//解码:String s = new String(b, "GBK");//b是字节数组
f.write(100);//最终显示为abcd
f.write("\n".getBytes());
//添加内容写ture,ture则覆盖之前的内容
FileOutputStream fa = new FileOutputStream("D:\\JAVA\\a.txt", ture);
f.write(97);//将会按ASCII转化
f.close();
fa.close();//结尾用close释放资源
FileInputStream
FileInputStream fis = new FileInputStream("D:\\JAVA\\a.txt");
//一次读取一个字节的情况
int c;
while ((c = fis.read()) != -1) {//read方法返回值为int类型,而读到-1代表文件已读取至末尾
System.out.println((char) c);//由于读取的类型为int要强制类型转换为char(按ASCII转化)
}
//一次读取一个字节数组
byte[] b = new byte[1024];//通常使用1024
//注意,当数组无法一次将所有的内容读完时,可能出现刚好读到换行的情况
//而在Windows里换行符为\r\n,其中\r和\n各算一个字节
//并且在字节中,二次读取的数据是覆盖一次读取的数据
//也就是说如果第一次读五个字节第二次读四个字节,那么在数组的第五个位置仍然是第一次读的数据
int len = 0;
//虽然我们在前面提到,数组重复读取是采用覆盖的方式的,这样一想,那len每次读出的长度不就是不变的吗(即数组的长度)
//事实并非如此,在执行len = fis.read(b)这一步时,len表示的是读取的新字节的个数,而不是数组的长度
while ((len = fis.read(b)) != -1) {
System.out.println(new String(b, 0, len));//len的目的是读几个展示几个
}
字符流
字符流=字节流+编码表(本质仍然是字节流)
字符流只能复制文本数据
字符输入流(OutputStreamWriter)
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\JAVA\\a.txt"));
//简化写法FileWriter fw = new FileWriter("D:\\JAVA\\a.txt");
osw.write(97);//注意使用字符流write时,如果不使用flush刷新或者不使用close释放资源,则无法写入(数据仍然在缓存区)
char[] ch = {'b', 'c', 'd'};
osw.write(ch);//bcd
osw.write(ch, 2, 1);//d
osw.write("ef");//ef
osw.write("gh", 0, 1);//g
osw.close();
字符输出流(InputStreamReader)
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\JAVA\\a.txt"));
//简化写法FileReader fr = new FileReader("D:\\JAVA\\a.txt");
//一次一个字节
int a = 0;
while ((a = isr.read()) != -1) {
System.out.println((char) a);
}
//一次一个数组
char[] c = new char[1024];
int len = 0;
while ((len = isr.read(c)) != -1) {
System.out.println(new String(c, 0, len));
}
isr.close();
缓冲流(提高效率)
字节缓存输出流(BufferedOutputStream)
FileOutputStream fos=new FileOutputStream("D:\\JAVA\\a.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write("you\r\n".getBytes());
bos.write("me\r\n".getBytes());
bos.close();
fos.close();//注意这里的顺序不能乱,一定要先释放缓冲流
字节缓存输入流(BufferedInputStream)
FileInputStream fis = new FileInputStream("D:\\JAVA\\a.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] b = new byte[1024];
int len = 0;
while ((len = bis.read(b)) != -1) {
System.out.println(new String(b, 0, len));
}
bis.close();
fis.close();
字符缓存输出流(BufferedWriter)
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\JAVA\\a.txt"));
bw.write(97);//注意使用字符流write时,如果不使用flush刷新或者不使用close释放资源,则无法写入(数据仍然在缓存区)
bw.newLine();//缓冲流特色换行方法
char[] ch = {'b', 'c', 'd'};
bw.write(ch);//bcd
bw.write(ch, 2, 1);//d
bw.write("ef");//ef
bw.write("gh", 0, 1);//g
bw.close();
字符缓存输入流(BufferedReader)
BufferedReader bf = new BufferedReader(new FileReader("D:\\JAVA\\a.txt"));
//一次一个字节
int a = 0;
while ((a = bf.read()) != -1) {
System.out.println((char) a);
}
//一次一个数组
char[] c = new char[1024];
int len = 0;
while ((len = bf.read(c)) != -1) {
System.out.println(new String(c, 0, len));
}
//缓冲流特色
String s;
while ((s = bf.readLine()) != null) {
System.out.println(s);//注意,这里只能是println而不能是printf,因为readline不读换行符
}
bf.close();
综合例题一
//输入学生信息并排序显示(优先级:成绩>年龄>输入顺序)
import java.io.*;
import java.util.Scanner;
import java.util.TreeSet;
public class draft {
public static void main(String[] args) throws IOException {
TreeSet<Student> t = new TreeSet<>();
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\JAVA\\a.txt"));
while (true) {
System.out.println("请输入学生姓名(输入no退出):");
Scanner sc = new Scanner(System.in);
String in = sc.nextLine();
if (in.equals("no")) {
break;
}
Student s = new Student();
s.name = in;
System.out.println("请输入学生年龄:");
s.age = sc.nextInt();
System.out.println("请输入学生成绩:");
s.grade = sc.nextDouble();
t.add(s);
}
for (Student s : t) {
bw.write(s.name + " " + s.age + " " + s.grade);
bw.newLine();
bw.flush();
}
bw.close();
BufferedReader br = new BufferedReader(new FileReader("D:\\JAVA\\a.txt"));
System.out.println("经排序,学生信息如下:");
String read;
while ((read = br.readLine()) != null) {
System.out.println(read);
}
br.close();
}
}
综合例题二
//复制单级文件夹
import java.io.*;
public class draft {
public static void main(String[] args) throws IOException {
File source = new File("D:\\JAVA\\tmp");//来源
File[] sf = source.listFiles();//获取来源中的所有文件file对象
File dest = new File("Draft", "tmp");//目的地
if (!dest.isDirectory()) {//创建目的文件夹
dest.mkdirs();
}
for (File f : sf) {//复制
copy(f, dest);
}
}
static void copy(File f, File d) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(d, f.getName())));
int len;
byte[] b = new byte[1024];
while ((len = bis.read(b)) != -1) {
bos.write(b);
}
bis.close();
bos.close();
}
}
综合实例三
import java.io.*;
public class draft {
public static void main(String[] args) throws IOException {
File source = new File("D:\\JAVA\\tmp");//来源
File[] sf = source.listFiles();//获取来源中的所有文件file对象
File dest = new File("Draft", "tmp");//目的地
if (!dest.isDirectory()) {//创建目的文件夹
dest.mkdirs();
}
for (File f : sf) {//复制
copy(f, dest);
}
}
static void copy(File f, File d) throws IOException {
if (f.isDirectory()) {//如果是文件夹
File newFile = new File(d, f.getName());
newFile.mkdirs();//在目的地创建文件夹
File[] files = f.listFiles();//将文件夹所有的内容收集
for (File file : files) {//复制
copy(file, newFile);
}
} else {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(d, f.getName())));
int len;
byte[] b = new byte[1024];
while ((len = bis.read(b)) != -1) {
bos.write(b);
}
bis.close();
bos.close();
}
}
}
特殊操作流
标准输入流(被static修饰,通过类名访问)
InputStream in = System.in;//通过多态创建对象,此时仅是字节流
int a;
while ((a = in.read()) != -1) {
System.out.println((char) a);
}
InputStreamReader isr = new InputStreamReader(in);//转换流InputStreamReader,将字节流转换为字符流
//一次一个数组
int len;
char[] b = new char[1024];
while ((len = isr.read(b)) != -1) {
System.out.println(new String(b, 0, len));
}
//缓冲流特色
BufferedReader br = new BufferedReader(isr);
String s;
while ((s=br.readLine())!=null){
System.out.println(Integer.parseInt(s));//这时可以使用封装类方法来将String转换为其它类型,但是比较麻烦
}
//JAVA提供了十分方便的类Scanner来帮助我们
Scanner sc = new Scanner(System.in);
标准输出流(被static修饰,通过类名访问)
System.out.println();
字节打印流(PrintStream)
PrintStream ps = new PrintStream("D:\\JAVA\\tmp\\a.txt");
ps.println(98);
ps.println();
ps.print(97);
ps.println();
ps.close();
字符打印流(PrintWriter)
PrintWriter pw = new PrintWriter("D:\\JAVA\\tmp\\a.txt");
pw.println(97);//pw.print(97)+pw.print(\r\n)
pw.flush();//需要刷新
//字符打印流有一种自动刷新的方法
PrintWriter pwf=new PrintWriter(new FileWriter("D:\\JAVA\\tmp\\a.txt"),true);
pw.println(97);//这样就等于pw.print(97)+pw.print(\r\n)+pw.flush()
对象序列化流(ObjectOutputStream)
public class draft {
public static void main(String[] args) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\JAVA\\tmp\\a.txt"));
oos.writeObject(new Student("小白", 18));
oos.close();
}
}
class Student implements Serializable {//实现Serializable接口的对象可以被序列化和反序列化
String name;
int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.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;
}
}
反序列化流(ObjectInputStream)
public class draft {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\JAVA\\tmp\\a.txt"));
Student s = (Student) ois.readObject();
System.out.println(s.name + " " + s.age);
ois.close();
}
}
class Student implements Serializable {//实现Serializable接口的对象可以被序列化和反序列化
transient String name;
int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.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;
}
}
//反序列化问题
//一、序列化后对类进行修改,是否可以正常反序列化
//不能,因为版本发生改变,但是可以将版本设为默认值 private static final long serialVersionUID = 42L;
//二、如果有不想序列化的信息怎么办
//用transient修饰