IO
文件
文件就是保存数据的地方
文件流:文件在程序中是以流的形式来操作的
流:数据在数据源(文件)到程序(内存)之间经历的路径
输入流:数据从数据流到程序的路径
输出流:数据从程序流到数据源的路径。
输入和输出是以Java程序为参考点,从Java程序流出就是输出流,流入就是输入流
创建文件方法
- new File(String path),使用文件路径创建
- new File(File parentPath,String path),使用父文件和要创建的文件创建
- new File(new parentPath,String childPath),使用父文件目录和子文件创建
public void create1() {
String path = "e:\\new1.txt";
File file = new File(path);//创建文件对象
//将文件在磁盘中创建
try {
file.createNewFile();
System.out.println("文件创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
public void create2(){
String parentPath = "e:\\";
File parentFile = new File(parentPath);//创建父文件目录
String fileName = "new2.txt";
File file = new File(parentFile, fileName);
try {
file.createNewFile();
System.out.println("创建文件成功");
} catch (IOException e) {
e.printStackTrace();
}
}
public void create3(){
String parentPath = "e:\\";
String childPath = "new3.txt";
File file = new File(parentPath, childPath);
try {
file.createNewFile();
System.out.println("文件创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
只有调用createNewFile才会真正在磁盘中创建文件
获取文件相关信息
//获取文件相关信息
String path = "e:\\new1.txt";
File file = new File(path);
System.out.println("文件名:" + file.getName());//获取文件名
System.out.println("文件绝对路径:" + file.getAbsolutePath());//获取文件绝对路径
System.out.println("文件的父级目录:" + file.getParent());//获取文件父级目录
System.out.println("文件的大小(字节):" + file.length());//获取文件的大小
System.out.println("文件是否存在: " + file.exists());//查看文件是否存在
System.out.println("文件是否是一个文件: " + file.isFile());//查看文件是否是一个文件
System.out.println("文件是否是一个目录: " + file.isDirectory());//查看文件是否是一个目录
//目录和文件的删除操作,只能删除空目录
String filepath = "e:\\new1.txt";
File file = new File(filepath);
if(file.exists()){
//判断文件是否存在,文件就删除,不存在提示信息
if(file.delete()){//delete删除文件
System.out.println(filepath + "删除成功");
}else{
System.out.println(filepath + "删除失败");
}
}else{
System.out.println(filepath + "文件不存在");
}
String directory = "e:\\demo1";
File file = new File(directory);//在Java中目录也是当成文件来处理
if(file.exists()){
//目录存在,删除目录
if(file.delete()){//delete目录
System.out.println(directory + "目录删除成功");
}else{
System.out.println(directory + "目录删除失败");
}
}else{
//目录不存在
System.out.println(directory + "不存在");
}
//创建目录 e:\a\b\c
String path = "e:\\a\\b\\c";//创建多级目录
File file = new File(path);
if(file.exists()){
//查看目录是否存在,存在不创建,提示信息
System.out.println(path + "目录已经存在");
}else{
if(file.mkdirs()){
//mkdirs创建多级目录,创建一级目录只需要mkdir()
//目录创建成功
System.out.println(path + "创建成功");
}else{
System.out.println(path + "创建失败");
}
}
IO流原理及流的分类
IO技术是非常实用的技术,用于处理数据传输,比如读写文件,网络传输等。
在Java程序中对于数据的输入和输出以“流"的形式进行
java.io包下面提供了各种流的接口和实现类,用以获取不同类型的数据并通过方法输入输出数据
输入:读取外部数据(外部不仅仅是文件,也可以是数据库,网络中的数据)到程序中
输出:将程序中的数据输出到外部
流的分类:
- 按操作数据单位的不同分为:字节流、字符流
- 按照数据流的流向不同分为:输入流、输出流
- 按照流的角色不同分为:节点流、处理流/包装流
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
![]() |
字节输入流InputStream
InputStream是所有字节输入流的超类,是一个抽象类,常用子类有:
- FileInputStream 文件输入流
- BufferedInputStream 缓冲文件输入流
- ObjectInputStream 对象字节输入流
FileInputStream
//方式一,使用read
//从文件中读取文件,使用FileInputStream
String path = "e:\\hello.txt";
FileInputStream fileInputStream = null;//定义文件字节输入流
int read = 0;
try {
fileInputStream = new FileInputStream(path);
//read,从该输入流读取一个字节的数据。数据的下一个字节,如果达到文件的末尾,返回-1 。
while((read = fileInputStream.read()) != -1){
System.out.print((char)read);//输出数据
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭IO资源
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//方式2使用read(byte[])
String path = "e:\\hello.txt";
FileInputStream fileInputStream = null;
byte[] buff = new byte[8];//每次读取8个字节
int length = 0;//每次实际读取数据字节数
try {
fileInputStream = new FileInputStream(path);
//使用read(byte[])每次读取一个指定数目的字节数,返回值是实际读取的字节数,如果返回-1表示结束
while((length = fileInputStream.read(buff)) != -1){
//将每次读取的字节数组转换成字符输出
System.out.print(new String(buff,0,length));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭IO资源
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
文件拷贝
//实现把E:\\test.jpg复制一份,E:\\test1.jpg
String srcPath = "e:\\test.jpg";
String descPath = "e:\\test1.jpg";
FileInputStream fileInputStream = null;//创建文件输入流
FileOutputStream fileOutputStream = null;//创建文件输出流
try {
fileInputStream = new FileInputStream(srcPath);
fileOutputStream = new FileOutputStream(descPath);
byte[] buff = new byte[1024];//每次读取1024字节大小的数据
int length = 0;//实际读取的大小
while((length = fileInputStream.read(buff)) != -1){
fileOutputStream.write(buff,0,length);
fileOutputStream.flush();//刷新缓冲区
}
System.out.println("复制完成");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileInputStream.close();//关闭IO
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
字节输出流OutputStream
FileOutputStream文件字节输出流
//使用outputStream将数据写入到文件
String path = "e:\\a.txt";//将文件写入到该地址
FileOutputStream fileOutputStream = null;
try {
//这个方式输入默认是覆盖新内容,如果文件存在就直接写入,文件不存在,就创建文件
fileOutputStream = new FileOutputStream(path,true);//第二次参数是用来确定是追加内容还是覆盖内容
//写入一个字符
//fileOutputStream.write('H');
//写入一个字节数组
String str = "hello";
// fileOutputStream.write(str.getBytes());
//写入指定字节数组的指定大小
//fileOutputStream.write(str.getBytes(),0,str.getBytes().length);
fileOutputStream.write(str.getBytes(),0,3);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();//关闭IO资源
} catch (IOException e) {
e.printStackTrace();
}
}
字符输入流Reader
字符输入流
//使用字符输入流FileReader从文件中读取内容
String path = "e:\\story.txt";
FileReader fileReader = null;
try {
fileReader = new FileReader(path);
int reader = 0;
char[] buff = new char[20];//每次读取二十个字符
int length = 0;//记录实际长度
// while((reader = fileReader.read()) != -1){//每次读取一个字符
// System.out.print((char) reader);
// }
while((length = fileReader.read(buff)) != -1){
System.out.print(new String(buff,0,length));//每次读取一组数据,当等于-1的时候表示数据读取完成
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fileReader != null){
try {
fileReader.close();//关闭IO资源
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符输出流Writer
字符输出流,在写出之前一定要关闭或者刷新缓冲区
String path = "e://story1.txt";
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter(path);
//写出单个字符
fileWriter.write('H');
//写出字符数组
fileWriter.write("hello".toCharArray());
//写出字符串
fileWriter.write("测试");
fileWriter.flush();//刷新缓冲区写出数据
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭IO资源
if(fileWriter != null){
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
节点流和处理流
节点流可以从一个特点的数据源读取数据,比如:FileReader、FileWriter
处理流(包装类)是连接在已经存在的流(节点流和处理流)之上,为程序提供更为强大的读取功能,比如:BufferedReader。
节点流和处理流的区别和联系
-
节点流是底层流/低级流,直接跟数据源相连
-
处理流(包装类)包装节点流,即可以消除不同节点流的实现差异,也可以提供更方便的方法来进行输入输出
-
处理流对节点流进行了包装,使用了修饰器设计模式,不会直接与数据源相连。
//模拟修饰器模式 //相当于父类Reader public abstract class Reader_ { public abstract void read();//读内容 } //相当于节点流 public class FileReader_ extends Reader_ { @Override public void read() { System.out.println("读取文件内容"); } } public class ArrayReader_ extends Reader_ { @Override public void read() { System.out.println("读取数组内容"); } } //相当于处理流,内部封装父类对象属性,对原有功能进行增强 public class BufferedReader_ extends Reader_ { private Reader_ reader_; public BufferedReader_(Reader_ reader_){ this.reader_ = reader_; } @Override public void read() { //对读进行其它处理,增加缓存,对原有功能进行增强 System.out.println("增加缓存"); for(int i = 0; i < 5; i++){ this.reader_.read(); } System.out.println("读取完成,输出"); } } //测试 BufferedReader_ bufferedReader_ = new BufferedReader_(new FileReader_()); bufferedReader_.read();
处理流的主要功能主要体现在下面两个方面:
- 性能的提高,主要增加缓冲的方式来提高输入输出的效率
- 操作的便捷,处理流可以提供跟便捷的方法来一次性输入输出大批量的数据,使用更加灵活
BufferedReader和BufferedWriter
//使用字符输入处理流读取文件内容
String srcPath = "e:\\story.txt";
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(srcPath));
String line = null;//每次读取一行数据
while((line = bufferedReader.readLine()) != null){
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bufferedReader != null){
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//使用字符输出处理流输出数据
String descPath = "e:\\new5.txt";
BufferedWriter bufferedWriter = null;
try {
bufferedWriter = new BufferedWriter(new FileWriter(descPath,true));
bufferedWriter.write("Hello world!");
bufferedWriter.newLine();//新行
bufferedWriter.write("测试");
bufferedWriter.newLine();
System.out.println("写出完成");
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bufferedWriter != null){
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedInputStream和BufferedOutputStream
String srcPath = "e:\\test.jpg";
String descPath = "e:\\test1.jpg";
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream(srcPath));
bos = new BufferedOutputStream(new FileOutputStream(descPath));
byte[] buff = new byte[1024];
int length = 0;
while((length = bis.read(buff)) != -1){
bos.write(buff,0,length);
}
System.out.println("拷贝完成");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
对象流
ObjectInputStream和ObjectOutputStream是对象流,能够进行序列化和反序列化
序列化:就是在保存数据的时候,保存数据的值和类型
反序列化:就是在恢复数据的时候,恢复数据的值和类型
需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,这个类必须实现下面两个接口之一:
- Serializable 标记接口
- Externalizable
ObjectOutputStream序列化功能,ObjectInputStream反序列化功能
//序列化对象,注意使用的方法不是write
String path = "e:\\data.dta";
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(path));
oos.writeInt(10);//序列化 int,会自动装箱成Integer
oos.writeBoolean(true);//序列化,会自动装箱成Boolean
oos.writeChar('H');//序列化 ,会自动装箱成Character
oos.writeUTF("hello");//序列化String
oos.writeObject(new Dog("小黄",10));//序列化对象
System.out.println("序列化完成");
} catch (IOException e) {
e.printStackTrace();
} finally {
if(oos != null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//反序列化
String path = "e:\\data.dta";
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(path));
//进行反序列化,注意读取顺序要和写入顺序一致
System.out.println(ois.readInt());
System.out.println(ois.readBoolean());
System.out.println(ois.readChar());
System.out.println(ois.readUTF());
Object o = ois.readObject();
System.out.println("运行类型:" + o.getClass());
//向下转型读取对象方法
Dog dog = (Dog) o;
System.out.println(dog.getName());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
if(ois != null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意事项:
- 序列化和反序列化的读写顺序要一致
- 要求序列化和反序列化的对象实现Serializable接口
- 序列化的类中建议添加SeriaVersionUID,为了提高版本兼容性 private static final long SeriaVersionUID = 1L;
- 序列化的时候,默认将所有的属性都序列化,但除了static和transient修饰的成员
- 序列化对象的时候,要求属性的类型也需要实现Serializable接口
- 序列化具备继承性,如果某个类已经实现了序列化,那么它的所有子类已经默认实现了序列化
标准输入输出流
System.in 标准输入 类型是:InputStream 运行类型是BufferedInputStream 默认就是键盘
System.out 标准输出 类型是PrintStream 运行类型是PrintStream 默认就是显示器
转换流
InputStreamReader:可以将一个字节输入流转换成字符输入流
OutputStreamWriter:可以将一个字节输出流转换成字符输出流
String path = "e:\\hello.txt";
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(
new InputStreamReader(new FileInputStream(path),"gbk"));//指定编码为GBK,解决乱码问题
String line = bufferedReader.readLine();
System.out.println(line);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bufferedReader != null){
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//转换成字符输出流
String path = "e:\\hello1.txt";
BufferedWriter bufferedWriter = null;
try {
bufferedWriter = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(path),"GBK"));
bufferedWriter.write("hello 无涯子");
bufferedWriter.newLine();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bufferedWriter != null){
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
打印流
打印流只有两种:PrintStream、PrintWriter
PrintStream out = System.out;
out.println("hello");
//写入方法是将内容写入到标准输入,就是显示器
try {
System.setOut(new PrintStream("e:\\f1.txt"));//重置输出的地方
System.out.println("hello");
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
PrintWriter printWriter = null;
String path = "e:\\f2.txt";
try {
printWriter = new PrintWriter(new FileWriter(path));
printWriter.println("hello ______");
} catch (IOException e) {
e.printStackTrace();
} finally {
printWriter.close();//一定要关闭打印流,不然不会写入到文件中
}
Properties
使用Properties读取文件
Properties properties = new Properties();//创建Properties集合
try {
properties.load(new FileReader("src\\mysql.properties"));//加载文件
properties.list(System.out);//读取所有属性
String user = properties.getProperty("user");//读取单个属性
String ip = properties.getProperty("ip");
System.out.println(user);
System.out.println(ip);
} catch (IOException e) {
e.printStackTrace();
} finally {
}
使用Properties写入数据到文件
Properties properties = new Properties();
properties.setProperty("user","无涯子");
properties.setProperty("pwd","123");
//写出到文件
try {
//使用字符输出流将信息写出到文件
properties.store(new FileWriter("src\\my.properties"),null);
System.out.println("文件写出成功");
} catch (IOException e) {
e.printStackTrace();
}
使用Properties修改文件内容,使用setProperties重新设置即可。