1.IO流概述
- I:Input O:Output,通过IO流可以完成硬盘文件的读和写
- IO流的分类:
(1)输入输出流(按照流的方向):以内存为参照物,往内存中去,叫做输入(读);从内存中出来,叫做输出(写)
(2)字节流(按字节方式读取数据):一次读取1个字节,这种流是万能的
(3)字符流(按字符方式独居数据):一次读取1个字符,方便读取普通文本文件,不能读取图片、声音、视频等 - java中主要研究如何new流对象,每个流的特点、常用方法
- Java IO流中的四大家族InputStream(字节输入流)、OutputStream(字节输出流)、Reader(字符输入流)、Writer(字符输出流)。都是抽象类,都实现了Closeable接口,都有close()方法;输出流都实现了Flushable接口,都有flush()方法,用来将管道中剩余为输出的数据强行输出完,否则会导致丢失丢失数据
注意:类名以Stream结尾的为字节流,以Reader\Writer结尾的为字符流 - java.io标下需要掌握的流有16个:
(1)文件专属: - FileInputStream
- FileOutputStream
- FileReader
- FileWriter
(2)转换流:(将字节流转换为字符流) - InputStreamReader
- OutputStreamReader
(3)缓冲流专属: - BufferedReader
- BufferedWriter
- BufferedInputStream
- bufferedOutputStream
(4)数据流专属: - DateInputStream
- DateOutputStream
(5)标准输出流 - PrintWriter
- PrintStream
(6)对象专属流 - ObjectInputStream
- ObjectOutputStream
2.文件流
2.1FileInputStream流
2.1.1创建流、read和close方法
public class Test {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("tempfile.txt");//绝对路径或相对路径(工程的根为IDEA默认当前路径)
byte[] bytes = new byte[4];
//int read(byte[] b)一次读取b.length个字节,提高程序执行效率
int readCount = 0;
// int readDate = fis.read();这个方法的返回值为读取到的字节本身,文件末尾读不到数据返回-1
while ((readCount = fis.read(bytes)) != -1) { //fis.read(bytes)返回值是读取到的字节数量
System.out.println(new String(bytes, 0, readCount));//按照读取的字节数量将数组转换为字符
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {//避免空指针异常,流为null是不必关闭
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2.1.2avaiable方法
int avaiable():返回流中剩余的没有读到的字节数量
public class Test {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("tempfile.txt");
byte[] bytes = new byte[fis.avaiable()];//获取文件字节数量,不适合太大的文件
int readCount = fis.read(bytes);
System.out.println(new String(bytes));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2.1.3skip方法
long skip(long n):跳过几个字节不读
fis.skip(3);//跳过前3个字节不读
int next = fis.read();//读取下一个字节
2.2FileOutputStream流
public class FileOutputStreamTest {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
//fos = new FileOutputStream("myfile");文件不存在时会自动创建。这种方式会将源文件情况再写入
fos = new FileOutputStream("myfile",true);//以追加的方式在文件末尾写入,不会清空源文件内容
byte[] bytes = {97, 98, 99};
fos.write(bytes);//全部写出
fos.write(bytes, 0, 2);//写ab
String s = "日天家的猫";
byte[] bs = s.getBytes();//将字符串转换为byte数组
fos.write(bs);
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2.3FileReader流
针对普通文本
public class FileReaderTest {
public static void main(String[] args) {
FileReader reader = null;
try {
reader = new FileReader("myfile");
//char chars = new chars[4];
//reader.read(chars);
//for(char c:chars){System,out.println(c);} 往char数组中读
char[] chars = new char[4];//一次读取4个字符
int readCound = 0;
while ((readCound = reader.read(chars)) !=-1){
System.out.println(new String(chars,0,readCound));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2.4FileWriter流
针对普通文本
public class FileWriterTest {
public static void main(String[] args) {
FileReader fr = null;
try {
fr = new FileReader("myfile",true);
char[] chars = {'我','和','你'};
fr.write(chars);
fr.write(chars,0,1);
fr.write("心连心");
fr.write("\n");//换行
fr.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3.缓冲流与转换流
3.1BufferedReader与InputStreamReader
BufferedReader:带有缓冲区的字符输入流,不需要自定义char数组或者byte数组,自带缓冲
//当一个流的构造方法中需要一个流的时候,被传进来的流叫做“节点流”,外部负责包装的流叫“包装流”或“处理流”
FileReader reader = new FileReader("myfile.java");
BufferedReader br = new BufferedReader(reader);
String s = null;
//br.readLine()方法读取一个文本行,但不带换行符
while((s = br.readLinr()) != null){System.out.println(s);}
br.close();//对于包装流来说,只需要关闭最外层流就行,里面的节点流会自动关闭
通过转换流将字节流装换为字符流
FileInputStream in = new FileInputStream("myfile2.java");
InputStreamReader reader = new InputStreamReader(in);
BufferedReader br = new BufferedReader(reader);
//BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("myfile2.java")));
String s = null;
while((s = br.readLinr()) != null){System.out.println(s);}
br.close();
3.2BufferedWriter与InputStreamWriter
BufferedWriter:带有缓冲的字符输出流
通过转换流将字节流装换为字符流
BufferedWriter out = new BufferedWriter(new InputStreamWriter(new FileOutputStream("myfile3.java",true)));
out.write("Hello");
out.write("\n");
out.write("World");
out.flush();
out.close();
3.3BufferedInputStream与BufferedOutputStream
需包装字节流
4.数据流
4.1DateOutputStream
数据字节输出流可以将数据连同数据类型一并写入文档(非普通文档)
DateOutputStream dos = new DateOutputStream(new FileOutputStream("date"));
int a = 24;
double b = 3.14
char c = 'a';
boolean sex = true;
dos.writeInt(a);//将数据与数据类型一同写入
dos.writeDouble(b);
dos.writeChar(c);
dos.writeBoolean(sex);
dos.flush();
dos.close();
4.2DateInputStream
数据字节输入流
DateOutputStream写的文件,必须由DateInputStream去读,并且读的时候需要记得奥写入的顺序,只有顺序一致,才能去除正确的数据
DateInputStream dis = new DateInputStream(new FileInputStream("date"));
int a = dis.readInt();
double b = dis.readDouble();
char c = dis.readChar();
boolean sex = dis.readBoolean();
dis.close();
5.标准输出流
5.1PrintStream
标准字节输出流
System.out.println("HelloWorld");
PrintStream ps = System,out;
ps.println("HelloWorld");
//标准输出流不需要手动close()关闭
改变标准输出流的输出方向,指向“Log”文件
PrintStream printStream = mew PrintStream(new FileOutputStream("Log",true));
System.setOut(printStream);
System.out.println("HelloWorld");
总结System类使用过的属性和方法
System.gc();
System.currentTimeMillis();
PrintStream ps = System.out;
System.exit(0);
System.arraycopy(...);
5.1PrintWriter
标准字符输出流,构造方法中传字符
6.对象流
6.1对象的序列化和反序列化
6.2序列化版本号
标志接口,没有具体代码,JVM对实现了标志接口的类可能进行特殊待遇。
参与序列化和反序列化的对象,必须实现Serializable接口。JVM就看到后,自动生成一个序列化版本号。
Java语言中区分类的机制:(1)类名(2)类名一样,通过序列化版本号区分
自动生成序列版本号的缺陷:代码确定或不可修改,修改重新编译会生成新的序列版本号,JVM会认为这是一个全新的类
结论:凡是一个类实现了Serializable接口,建议提供一个固定不变的序列化版本号(可有IDEA自动生成)
6.3序列化的实现ObjectOutputStream流
import java.io.Serializable;
public class Student implements Serializable {
private static final long serialVersionUID = -5087935970704858855L;
private int no;
private String name;
public Student() {}
public Student(int no, String name) {this.no = no;this.name = name;}
public int getNo() {return no;}
public void setNo(int no) {this.no = no;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public String toString() {return "Student{" +"no=" + no +", name='" + name + '\'' + '}';}
}
public class ObjectOutputStreamTest {
public static void main(String[] args) throws Exception{
Student s = new Student(1,"zhangsan");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("students"));
oos.writeObject(s);
oos.flush();
oos.close();
}
}
一次序列化多个对象,可以采用List集合等方式
public class ObjectOutputStreamTest02 {
public static void main(String[] args) throws Exception{
List<Student> studentList = new ArrayList<>();
studentList.add(new Student(1,"zhangsan"));
studentList.add(new Student(2,"lisi"));
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("students2"));
oos.writeObject(studentList);
oos.flush();
oos.close();
}
}
6.4反序列化的实现ObjectInputStream流
public class ObjectInputStreamTest01 {
public static void main(String[] args) throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("students"));
Object obj = ois.readObject();
System.out.println(obj);
ois.close();
}
}
一次序列化多个对象
public class ObjectInputStreamTest02 {
public static void main(String[] args) throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("students2"));
List<Student> studentList = (List<Student>)ois.readObject();
for(Student student:studentList){ System.out.println(student);}
ois.close();
}
}
6.5 transient关键字
表示游离,不参与序列化
private transient String name;
7.File类
File对象是文件和目录路径名的抽象表示形式
File类中的常用方法
//创建File对象
File f1 = new File("D:\\file");
//判断是否存在
System.out.println(f1.exists());
//以文件形式创建,以目录形式创建
if (!f1.exists()) {
f1.createNewFile();
}
if (!f1.exists()) {
f1.mkdir();
}
//创建多重目录
File f2 = new File("D:/a/e/f/d");
if (!f2.exists()) {
f2.mkdirs();
}
File f3 = new File("D:\\Steam\\steamapps");
//获得文件的父路径,以字符串或者File对象
String parentPath = f3.getPath();
File parentFile = f3.getParentFile();
System.out.println("绝对路径" + parentFile.getAbsolutePath());
//获取绝对路径
File f4 = new File("copy");
System.out.println("绝对路径" + f4.getAbsolutePath());
//获取文件名
File f5 = new File("D:\\develop\\Snipaste\\Snipaste.exe");
System.out.println("文件名" + f5.getName());
//判断是否是一个目录
System.out.println(f5.isFile());
//获取文件最后修改的时间
long haoMiao = f5.lastModified();
Date time = new Date(haoMiao);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String strTime = sdf.format(time);
System.out.println(strTime);
//获取文件大小
System.out.println(f5.length());
//File中的ListFiles方法 File[] listFiles()
File f6 = new File("D:\\SoftWare\\N0vaDesktop");
//获取当前目录下的所有子文件
File[] files = f6.listFiles();
for (File file : files) {
System.out.println(file.getAbsolutePath());
System.out.println(file.getName());
}
8.IO流和Properties集合的联合使用
8.1配置文件
经常改变的数据,可以单独写到一个文件中,使用程序动态读取,这样不需要重新编译,服务器也不需要重启
这种文件称为属性配置文件,建议以properties结尾。Properties是专门存放属性配置文件的一个类,内容格式为
key1=value
key2=value
#在属性配置文件中#为注释
#建议key与value间用“=”方式,不建议使用“:”,最好不要有空格
8.2使用示例
//uesrinfo.properties
username=admin
password=123
FileReader reader = new FileReader("uesrinfo");
Properties pro = new Properties;
pr.load(reader);//文件中的数据流顺着管道加载到Map集合中,等号左边为key,右边为value
String usename = pr.getProperty("username");
System.out.println(username);//admin
9.示例
9.1自定义日志工具
public class Logger {
public static void log(String msg) {
try {
PrintStream printStream = new PrintStream(new FileOutputStream("log.txt", true));
System.setOut(printStream);
Date nowTime = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd:mm:ss SSS");
String srtTime = sdf.format(nowTime);
System.out.println(srtTime + ":" + msg);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
//使用Logger.log("输出HelloWorld!");
9.2文件复制
使用FileInputStream+FileOutputStream完成文件的拷贝(一边读,一边写)
或则使用FileReader和FileWriter拷贝普通文本文件(能用记事本打开编辑)
public class CopyTest01 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("D:\\素材包\\bilidown\\Download\\AC\\1.9刺客信条:英灵殿.mp4");
fos = new FileOutputStream("D:\\1.9刺客信条:英灵殿.mp4");
byte[] bytes = new byte[1024*1024]; //一次拷贝1MB
int readCount = 0;
while((readCount=fis.read(bytes))!=-1){
fos.write(bytes,0,readCount);
}
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//分开处理异常,不然一个流关闭出现异常会影响另一个流的关闭
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis == null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
9.3拷贝目录
public class CopyAll {
public static void main(String[] args) {
File srcFile = new File("D:\\素材包\\素材");
File destFile = new File("C:\\");
copyDir(srcFile, destFile);
}
private static void copyDir(File srcFile, File destFile) {
if (!srcFile.isFile()) {
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream("srcFile");
String path = destFile.getAbsolutePath().endsWith("\\") ? destFile.getAbsolutePath() : destFile.getAbsolutePath() + "\\" + srcFile.getAbsolutePath().substring(3);
out = new FileOutputStream("");
byte[] bytes = new byte[1024 * 1024];
int readCound = 0;
while ((readCound = in.read(bytes)) != -1) {
out.write(bytes, 0, readCound);
}
out.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return;
}
File[] files = srcFile.listFiles();
for (File file : files) {
if (file.isDirectory()) {
String srcDir = file.getAbsolutePath();
String destDir = destFile.getAbsolutePath().endsWith("\\") ? destFile.getAbsolutePath() : destFile.getAbsolutePath() + "\\" + srcDir.substring(3);
File newFile = new File(destDir);
if (!newFile.exists()) {
newFile.mkdirs();
}
copyDir(file, destFile);
}
}
}
}
传送门
上一章:JavaSE进阶 第十一章 集合
下一章:JavaSE进阶 第十三章 多线程