IO流
- IO流
- 文件
- 什么是文件?
- 文件流
- 创建文件
- 方式一:完整路径
- 方式二:根据父目录文件和子路径创建**
- 方式三:根据父目录路径+子路径构建
- 小知识点:路径问题
- 对文件的常用操作
- 获取文件信息
- 对文件和目录的操作
- Java IO流原理及流的分类
- 概念:
- 流的分类:
- 字节流:
- 字符流:
- 文件和流的对比:
- 字节流:
- InputStream:字节输入流
- FileInputStream
- read()
- read(byte b[]):
- OutputStream:字节输出流
- FileOutputStream:
- write():放一个字节数
- write(byte[]):
- write(byte[],0,len):
- 细节注意点:
- 文件拷贝:
- 字符流
- FileReader:字符输入流
- FileWriter:字符输出流
- 构造器注意:
- 节点流和处理流
- 概念:
- 处理流的功能主要体现在以下两个方面:
- BufferedReader:字符输入处理流
- readline:
- BufferedWriter:字符输出处理流
- 字符处理流实现文件copy
- BufferedInputStream:字节输入处理流
- BufferedOutputStream:字节输出处理流
-
- 字节处理流实现音乐和视频等二进制文件copy
- 对象处理流
- ObjectOutputStream:对象输出流实现序列化
- ObjectInputStream:对象输入流实现反序列化
- 注意细节:
- 标准输入输出流
- 转换流
- InputStreamReader:字节转换字符输入流
- OutputStreamWriter:字节转换字符输出流
- 打印流
- PrintStream:字节打印流
- PrintWriter:字符打印流
- Properties类
- 文件
文件
什么是文件?
文件,对我们并不陌生,文件是保存数据的地方,比如大家经常使用的word文档,txt文件,excel文件...都是文件。它既可以保存一张图片,也可以保持视频,声音.
文件流
文件在程序中都是以流的形式来操作的
流:数据在数据源(文件)和程序(内存)之间经历的路径
输入流:数据从数据源(文件)到程序(内存)的路径
输出流:数据从程序(内存)到数据源(文件)的路径
创建文件
createNewFile()
三种方式
方式一:完整路径
注:在创建的时候,我们new File(),只是在内存中,只有调用到createNewFile()才会写入到硬盘
new File(String path)
@Test
public void crate1(){
String path="D:\\java高级部分\\JavaIo\\源\\One.txt";
File file = new File(path);
try {
file.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
方式二:根据父目录文件和子路径创建**
**new File(File parent,String child)
public void crate2(){
String path="Two.txt";
File file1 = new File("D:\\java高级部分\\JavaIo\\源");
File file2 = new File(file1,path);
try {
file2.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
方式三:根据父目录路径+子路径构建
new File(String parent, String child)
// 方式三:new File(String parent, String child)//根据父目录路径+子路径构建
@Test
public void crate3(){
String path="Three.txt";
String ParenPath="D:\\java高级部分\\JavaIo\\源";
File file2 = new File(ParenPath,path);
try {
file2.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
小知识点:路径问题
在文件创建时有一个注意点就是,就是文件的路径是D:/ 之类的,但是我们在程序写的时候必须是D://有一个转义符,或者写成D:
对文件的常用操作
获取文件信息
对文件和目录的操作
listFiles():将文件下的所有内容放到一个File数组里
public static void Test(String path){
File file = new File(path);
if (file.isDirectory()){
将文件下的所有内容放到一个File数组里
File[] files = file.listFiles();
for (int i = 0; i
创建:一级目录mkdir(),多级目录mkdirs()
删除:delete()
// 判断文件是否存在,存在就删除,不存在创建
@Test
public void c1(){
File file = new File("D:\\java高级部分\\JavaIo\\源\\Four.txt");
if (file.exists()){
if (file.delete()){
System.out.println("删除成功");
}
}else{
if ( file.mkdir()){
System.out.println("创建成功");
}
}
}
// 判断目录是否存在,存在就删除,不存在创建
// 在java中编程中,目录也被当成文件
@Test
public void c2(){
File file = new File("D:\\java高级部分\\JavaIo\\源\\sb");
if (file.exists()){
if (file.delete()){
System.out.println("删除成功");
}
}else{
if ( file.mkdir()){
System.out.println("创建成功");
}
}
}
Java IO流原理及流的分类
概念:
- I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理数据传输。如读/写文件,网络通讯等。
- Java程序中,对于数据的输入/输出操作以”流(stream)”的方式进行。
- java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过方法输入或输出数据
输入流:数据从数据源(磁盘,网络,光盘)到程序(内存)的路径
输出流:数据从程序(内存)到数据源(磁盘,光盘,网络)的路径
流的分类:
按操作数据单位:字节流(8 bit),字符流(字符)
按流的方向:输入流,输出流
按流的角色的不同:字节流,处理流/包装流
字节流:
InputStream();
OutputStream()
字符流:
Writer()
Reader()
文件和流的对比:
字节流:
InputStream:字节输入流
FileInputStream
read()
@Test
public void readFile1(){
// 将文件放入内存中
File file = new File("D:\\java高级部分\\JavaIo\\源\\FileInputStream");
// 创建一个文件输入流
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
// 定义一个变量用于接收流的数据
int readDate=0;
// read方法读取一个字节,如果读到最后一个字节就返回-1
while ((readDate=fileInputStream.read())!=-1){
System.out.print((char)readDate);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
read(byte b[]):
//使用read(byte[])优化
@Test
public void readFile2(){
File file = new File("D:\\java高级部分\\JavaIo\\源\\FileInputStream");
FileInputStream fileInputStream = null;
byte buf[]=new byte[3];
int readbuf=0;
try {
fileInputStream = new FileInputStream(file);
// read方法读取一个字节,如果读到最后一个字节就返回-1
while ((readbuf=fileInputStream.read(buf))!=-1){
// 从该输入流读取最多 buf.length个字节的数据为字节数组。
System.out.print(new String(buf,0, readbuf));
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
OutputStream:字节输出流
FileOutputStream:
write():放一个字节数
write(byte[]):
public void writeStream1(){
File file = new File("D:\\java高级部分\\JavaIo\\源\\FileOutputStream");
if (file.exists()){
file.delete();
}else{
file.mkdir();
}
String buf="刘超真帅";
FileOutputStream outps=null;
try {
outps = new FileOutputStream(file);
//将字符串转换为字节数组
outps.write(buf.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
outps.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
write(byte[],0,len):
从位于偏移量 off
的指定字节数组写入 len
字节到该文件输出流。
细节注意点:
当我们正常写入时,会覆盖原来文件的内容
FileOutputStream outps = new FileOutputStream(file,true);
这个时候在构造器加一个true,就不会覆盖会追加到内容后
文件拷贝:
public void copy1(){
File file = new File("D:\\java高级部分\\JavaIo\\源\\ALisa - 溯Reverse(治愈版).mp3");
FileInputStream FIus=null;
FileOutputStream FOps=null;
int readlen=0;
try {
FIus = new FileInputStream(file);
byte buf[]=new byte[1024];
FOps = new FileOutputStream("D:\\java高级部分\\JavaIo\\源\\ALisa - 溯Reverse(治愈版)2.mp3");
while ((readlen=FIus.read(buf))!=-1){
//边读边写
FOps.write(buf,0, readlen);
//这里不要用write(byte[]),因为固定死了读取整个数组长度的值,如果后面剩余的数量小于数组值,会填入很快空值
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
FIus.close();
FOps.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符流
FileReader:字符输入流
read()
read(byte[]):
// 一次读取多个字符
@Test
public void Reader2(){
File file = new File("D:\\java高级部分\\JavaIo\\源\\One.txt");
int Readdate=0;
FileReader reader = null;
char []buf=new char[8];
try {
reader = new FileReader(file);
while ((Readdate=reader.read(buf))!=-1){
System.out.print(new String(buf,0,Readdate));
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileWriter:字符输出流
构造器注意:
new FileWriter(path/file):覆盖模式
new fileWriter(path/file,true):追加模式
@Test
public void writer1(){
FileWriter fileWriter =null;
char []b=new char[]{'a','c','d'};
try {
fileWriter = new FileWriter("D:\\java高级部分\\JavaIo\\源\\Two.txt");
// Writer(char):写入单个字符
fileWriter.write('A');
// write(char[]):写入指定数组
fileWriter.write(b);
// write(char[],off,len):写入指定数组的指定部分
fileWriter.write(b,0,2);
// Writer(String):写入整个字符串
fileWriter.write("你好zz,");
// write(String,off,len):写入字符串的指定部分
fileWriter.write("你好傻逼",2,2);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
节点流和处理流
概念:
1.节点流就是从一个特定的数据源读写数据,如FileReader,FileWriter
有哪些字节流:
2.处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供
更为强大的读写功能,如BufferedReader、BufferedWriter [源码]
BufferReader类里有Reader,封装了一个字节流
处理流的功能主要体现在以下两个方面:
-
性能的提高:主要以增加缓冲的方式来提高输入输出的效率。
-
操作的便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量的数据,使
用更加灵活方便
BufferedReader:字符输入处理流
注意点:关闭处理流只需要关闭外层流就可以了,如果你关闭处理流,底层的节点流就会自己关闭
readline:
读取一行,末行返回null
@Test
public void Reader1(){
File file = new File("D:\\java高级部分\\JavaIo\\源\\One.txt");
String line;
BufferedReader bufferedReader =null;
try {
bufferedReader = new BufferedReader(new FileReader(file));
// readline()读取一行,末行返回null
while ((line=bufferedReader.readLine())!=null){
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
// 这里只需要关闭处理流,底层节点流自己会关闭
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedWriter:字符输出处理流
如果你是覆盖方式就是普通构造器:
如果你是追加方式,因为BufferWriter构造器没有,且底层是节点流在处理数据,所以追加就在节点流构造器加true就行
public void Writer1(){
BufferedWriter bufferedWriter =null;
try {
//覆盖模式:
bufferedWriter = new BufferedWriter(new FileWriter("D:\\java高级部分\\JavaIo\\源\\Three.txt"));
//追加模式:
bufferedWriter = new BufferedWriter(new FileWriter("D:\\java高级部分\\JavaIo\\源\\Three.txt"),true);
bufferedWriter.write('o');
bufferedWriter.write("耶");
bufferedWriter.newLine();//插入一个换行
bufferedWriter.write("你好帅b",0,3);
bufferedWriter.write(new char[]{'H','a'},0,1);
bufferedWriter.write(new char[]{'H'});
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符处理流实现文件copy
public void copy(){
File file = new File("D:\\java高级部分\\JavaIo\\源\\Three.txt");
File file2 = new File("D:\\java高级部分\\JavaIo\\源\\Three2.txt");
BufferedReader bufferedReader =null;
BufferedWriter bufferedWriter =null;
String line;
try {
bufferedReader = new BufferedReader(new FileReader(file));
// 追加
bufferedWriter = new BufferedWriter(new FileWriter(file2,true));
while ((line=bufferedReader.readLine())!=null){
// 读一行写一行
bufferedWriter.write(line);
// 读一行就换行
bufferedWriter.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
bufferedWriter.close();
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedInputStream:字节输入处理流
BufferedOutputStream:字节输出处理流
字节处理流实现音乐和视频等二进制文件copy
public void OutCopy(){
File file = new File("D:\\java高级部分\\JavaIo\\源\\img.png");
File file2 = new File("D:\\java高级部分\\JavaIo\\源\\img2.png");
byte []buf=new byte[1024];
BufferedInputStream bufferedInputStream =null;
BufferedOutputStream bufferedOutputStream =null;
try {
bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file2));
while ((bufferedInputStream.read(buf,0,buf.length)!=-1)){
bufferedOutputStream.write(buf,0,buf.length);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
bufferedOutputStream.close();
bufferedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
对象处理流
对象处理流不仅仅要保存对象的值,还要保存类型,这就涉及到了序列化的问题
- 序列化和反序列化
序列化就是在保存数据时,保存数据的值和数据类型
反序列化就是在恢复数据时,恢复数据的值和数据类型
需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该
类必须实现如下两个接口之一:
Serializable //这是一个标记接口Externalizable //该接口有方法要实现,所以一般不使用这个接口
ObjectOutputStream:对象输出流实现序列化
同样有一个构造器里有一个OutputStream的参数**,可以调用其他子类
public void Object1(){
File file = new File("D:\\java高级部分\\JavaIo\\源\\FileOutputStream");
ObjectOutputStream outputStream =null;
try {
outputStream = new ObjectOutputStream(new FileOutputStream(file));
outputStream.writeBoolean(true); //包装类Boolean实现了序列化接口
outputStream.writeByte(1);
outputStream.writeChar('l'); //Character实现类序列化接口
outputStream.writeDouble(3.22);
outputStream.writeUTF("你好");//写入字符串
//实现类的序列化时一定要注意这个类要自己实现序列化接口
outputStream.writeObject(new Person(20,"刘超"));
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ObjectInputStream:对象输入流实现反序列化
同样有一个构造器里有一个InputStream的参数,可以调用其他子类
public void Object1(){
File file = new File("D:\\java高级部分\\JavaIo\\源\\FileOutputStream");
ObjectInputStream Ois =null;
try {
Ois = new ObjectInputStream(new FileInputStream(file));
// 读取的顺序必须跟序列化顺序一样,因为序列化有数据类型,所以你反序列化类型必须相同
System.out.println(Ois.readBoolean());
System.out.println(Ois.readByte());
System.out.println(Ois.readChar());
System.out.println(Ois.readDouble());
System.out.println(Ois.readUTF()); //读取字符串
System.out.println(Ois.readObject());
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
Ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意细节:
- 序列化和反序列化顺序一致,不然会报错
- 要求序列化或者反序列的对象必须实现Serializable
- 序列化的类中建议添加SerializableUID,提高版本兼容性
- 序列化对象中,默认将所有属性都序列化,但除了static或transient修饰的成员
- 序列化对象时,要求里面的属性也实现序列化接口
当你在一个实现序列化接口的类里,里面有一个引用数据类型,并且这个类没有实现接口就会报错,其他基本数据类型的属性,由于包装类其实都实现了序列化了,所以没问题
6.序列化具有可继承性,如果某类实现了序列化,那么它的子类也默认实现了序列化
标准输入输出流
System.in==>InputStream 设备:键盘
System.out==>PrintStream 设备:显示器
public static void main(String[] args) {
// 输入流
// 编译时:public final static InputStream in = null;
// 运行时:BufferedInputStream
InputStream in = System.in;
System.out.println(in.getClass());
// 输出流
// 编译时: public final static PrintStream out = null;
// 运行时:PrintStream
System.out.println(System.out.getClass());
}
转换流
InputStreamReader:字节转换字符输入流
Reader的子类
此时的文件编码格式为ANSI
public void Code1(){
File file = new File("D:\\java高级部分\\JavaIo\\源\\Three.txt");
char buf[]=new char[1024];
String b;
InputStreamReader ISR =null;
FileInputStream FIS =null;
BufferedReader BR=null;
try {
FIS = new FileInputStream(file);
此时的GBK对应着文件的编码格式
// 将字节处理流FileInputStream转换成字符流InputStreamReader,并指定编码格式GBk
ISR = new InputStreamReader(FIS,"GBk");
// 再把流丢到处理流里处理
BR=new BufferedReader(ISR);
while ((b=BR.readLine())!=null){
System.out.print(b);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
// 同样只关闭外层流
BR.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
OutputStreamWriter:字节转换字符输出流
Writer的子类
public void OW1() throws IOException {
File file = new File("D:\\java高级部分\\JavaIo\\源\\Five.txt");
OutputStreamWriter OSW = new OutputStreamWriter(new FileOutputStream(file), "GBK");
OSW.write("你好");
// 这里发现不关流的化没有写入成功
写入内存缓冲区了,在不关闭、刷新情况下,或者内存缓冲没满时,是不会写入文档中,你必须加入flush()方法,或者关闭流,来刷新内存缓冲,这样就可以写到文档中
OSW.close();
}
注意点:输出的时候指定的编码格式就是设置那个文件的编码格式
打印流
打印流只有输出流(只能从程序打印出去)
PrintStream:字节打印流
public static void main(String[] args) throws FileNotFoundException {
PrintStream PS =System.out;
// public void print(String s) {
// if (s == null) {
// s = "null";
// }
// write(s); print底层是write输出
// }
PS.print("你好");
// 设置输出流输出的位置
System.setOut(new PrintStream("D:\\java高级部分\\JavaIo\\源\\Six.txt"));
System.out.println("刘超真帅");
}
PrintWriter:字符打印流
public static void main(String[] args) throws IOException {
// 打印流丢进去一个标准输出流就会在显示器控制台打印
// PrintWriter PW = new PrintWriter(System.out);
// PW.print("你好");
// 别忘了关流,不然缓存会导致无法写入
// PW.close();
// 打印流也是一个处理流
PrintWriter PW = new PrintWriter(new FileWriter("D:\\java高级部分\\JavaIo\\源\\Five.txt"),true);
PW.print("你好");
PW.close();
}
Properties类
专门用于读写配置文件的集合类(Hashtable的子类)
(1)配置文件的格式:
键=值
(2)键值对不需要有空格,值不需要用引号,默认类型为String
(3)常用方法:
load:加载配置文件
list:将整个文件(以打印处理流)输出到某个位置
getProperty(key):获取某个键的值
setProperty(key,value):设置键值对到Properties对象里,如果没有这个键就是创建,有就是修改
store(输出位置,注释):将Properties储存的键值对储存到配置文件中,如果含有中文,会储存为Unicode码
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
// 加载指定配置文件
properties.load(new BufferedReader(new FileReader("D:\\java高级部分\\JavaIo\\源\\My.properties")));
// 将整个Properties文件输出到某个地址
properties.list(System.out);
PrintWriter PW = new PrintWriter(new FileWriter("D:\\java高级部分\\JavaIo\\源\\One.txt"));
properties.list(PW);
PW.close();
// 获取某一个键的值
String user = properties.getProperty("User");
String password = properties.getProperty("password");
System.out.println(user+" "+password);
// 设置键值对到Properties对象里(此时并未储存,只是在内存中)
如果没有这个键就是创建,有就是修改
properties.setProperty("name","刘超");
properties.setProperty("age","20");
// 将Properties储存的键值对储存到配置文件中
第一个参数是:输出流的位置 第二个参数是:注释
properties.store(new FileWriter("D:\\java高级部分\\JavaIo\\源\\My2.properties"),null);
}