处理流之一:缓冲流
四种缓冲流:
BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter(对应相应的字节流,由名字即可判断)
缓冲流的作用:
提升文件读写的效率。
使用的方法:
处理文本文件的字符流:
BufferedReader read(char[ ] cbuffer) / readLine( )
BufferedWriter write(char[ ] cbuffer,0,len) / write(String) 、flush( ) (flush用于主动将内存中的数据写出到磁盘文件中)
处理非文本文件的字节流:
BufferedInputStream read(byte[ ] buffer)
BufferedOutputStream write(byte[ ] buffer,0,len)、flush( ) (flush用于主动将内存中的数据写出到磁盘文件中)
操作步骤:
①创建File的对象、文件流、缓冲流的对象
②使用缓冲流实现 读取数据 或 写出数据的过程:
- 读取:int read(char[ ] cbuffer)或int read(byte[ ] cbuffer)
- 写出:void write(char[ ] cbuffer,0, len) 或 void write(byte[ ] buffer,0, len)
③关闭资源
使用字节流复制文件的操作如下:
ini
void test1()
{
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try
{
//1.创建相关File类的对象
File srcFile = new File("输入流的图片文件.jpg");
File destFile = new File("输出流的成功文件(使用缓冲流).jpg");
//2.创建相关的字节流和缓冲流
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.数据的读写操作
byte[] buffer = new byte[1024];//1kb
int len;//记录每次读入到buffer中的字节的个数
while((len = bis.read(buffer)) != -1)
{
bos.write(buffer,0,len);
}
} catch (IOException e)
{
e.printStackTrace();
} finally
{
//4.关闭资源
//外层流的关闭(缓冲流),由于外层流的关闭会自动地内层流的关闭(节点流),所以可以省略内层流地关闭
try
{
if (bis != null)
{
bis.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
try
{
if (bos != null)
{
bos.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
}
}
用缓冲流来进行文件的读写和复制操作:
使用缓冲流的步骤与普通节点流的使用步骤类似,只要在缓冲流的构造器中放入相应的节点流的构造器,读写的操作只要调用构造器即可。
在关闭资源的操作时,只要关闭外层流(缓冲流)的构造器,相应的内层流(节点流)也会关闭,所以只需要有缓冲流的资源的关闭即可。
读取操作:
csharp
void test1()
{
BufferedReader br = null;
try
{
//1.创建File类的对象、流的对象
File file = new File("要用缓冲流复制的文本文件");
br = new BufferedReader(new FileReader(file));
//2.读取操作
//方式①
// char[] cbuffer = new char[20];
// int len;
// while((len = br.read(cbuffer)) != -1)
// {
// for (int i = 0; i < len; i++)
// {
// System.out.print(cbuffer[i]);
// }
// }
//方式②:readLine
String data;
while((data = br.readLine()) != null)
{
System.out.println(data);
}
} catch (IOException e)
{
e.printStackTrace();
}
finally
{
//3.关闭资源
try
{
br.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
复制操作:
ini
void test2()
{
BufferedReader br = null;
BufferedWriter bw = null;
try
{
//1.创建File类的对象,创建流的对象
File file1 = new File("要用缓冲流复制的文本文件");
File file2 = new File("使用缓冲流复制后的文本文件");
br = new BufferedReader(new FileReader(file1));
bw = new BufferedWriter(new FileWriter(file2));
//2.文件的读写操作
String data;
while((data = br.readLine()) != null)
{
bw.write(data);
bw.newLine();
}
} catch (IOException e)
{
e.printStackTrace();
} finally
{
//3.关闭资源
try
{
if(br != null)
{
br.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
try
{
if(bw != null)
{
bw.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
}
}
处理流之二:转换流
字符编码:字符、字符串、字符数组 ------> 字节、字节数组
字符解码:字节、字节数组 ------> 字符、字符串、字符数组
解码时使用的字符集必须与编码时的字符集一致。
转换流的使用:
①作用:转换流是字节与字符间的桥梁。实现字节和字符之间的转换。
②API:
InputStreamReader:将一个输入型的字节流转换为输入型的字符流。
OutputStreamWriter:将一个输出型的字符流转换为输出型的字节流。
若要将utf-8的文件转换为gbk的格式在控制台上显示,步骤如下:
ini
void test1()
{
InputStreamReader isr = null;
try
{
File f1 = new File("utf-8的文件");
FileInputStream fis = new FileInputStream(f1);
//isr = new InputStreamReader(fis);//此时使用idea默认的utf-8字符集
isr = new InputStreamReader(fis,"gbk");
char[] cbuffer = new char[20];
int len;
while((len = isr.read(cbuffer)) != -1)
{
String str = new String(cbuffer,0,len);
System.out.print(str);
}
} catch (IOException e)
{
e.printStackTrace();
} finally
{
try
{
if(isr != null)
isr.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
会发现,控制台上的字符信息会出现乱码,所以,输入时,编码和解码使用的字符集要一致。
若要将utf-8的格式的文件转换为gbk格式的文件存储,步骤如下:
ini
void test2()
{
InputStreamReader isr = null;//解码和编码的字符集要一致。
OutputStreamWriter osw = null;//参数要指明内存中的字符存储到文件中的字节过程使用的字符集。
try
{
//1.造File对象
File f1 = new File("utf-8的文件");
File f2 = new File("gbk的文件");
//2.造流
FileInputStream fis = new FileInputStream(f1);
isr = new InputStreamReader(fis,"utf-8");
FileOutputStream fos = new FileOutputStream(f2);
osw = new OutputStreamWriter(fos,"gbk");
char[] cBuffer = new char[10];
int len;
while ((len = isr.read(cBuffer)) != -1)
{
osw.write(cBuffer,0,len);
}
} catch (IOException e)
{
e.printStackTrace();
} finally
{
try
{
if (isr != null)
{
isr.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
try
{
if (osw != null)
{
osw.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
}
}
使用转换流的步骤为:
①将要操作的文件的File的对象作为参数,放入转换流的构造器中,创建转换流的对象。
注意:输入时,编码解码的字符集要一致,所以,InputStreamReader的对象的构造器中要放入与输入的文件一致的字符集。输出时,编码的字符集为相应的目标字符集,所以在OutputStreamWriter的对象的构造器中要放入相应的目标字符集。
②用InputStreamReader的对象和OutputStreamWriter的对象来进行相应的读写操作。
③关闭流资源
处理流之三:数据流
数据流:DataOutputStream、DataInputStream
DataOutputStream:将基本数据类型、String类型的变量写入输出流中,写出到文件中存储。
DataInputStream:从文件中读取基本数据类型、String类型的变量的数据,还原为基本数据类型、String类型的变量在内存中使用。
DataOutputStream中的方法:
byte readByte() | int readInt() |
float readFloat() | char readChar() |
short readShort() | long readLong() |
double readDouble() | boolean readBoolean() |
String readUTF() (读取String类型的方法) | void readFully(byte[] b) (读取字节数组的方法) |
DataInputStream中的方法:
byte writeByte() | int writeInt() |
float writeFloat() | char writeChar() |
short writeShort() | long writeLong() |
double writeDouble() | boolean writeBoolean() |
String readUTF() (写入String类型的变量的方法) | void readFully(byte[] b) (写入字节数组的变量的方法) |
数据流的弊端:
只支持基本数据类型和String类型的变量的读写,而不支持其他引用数据类型的读写。所以,涉及到其他的引用数据类型的读写,要使用对象流。
处理流之四:对象流
对象流:ObjectOutputStream、ObjectInputStream
ObjectOutputStream:将Java基本数据类型的的变量和引用数据类型的变量写入字节输出流中。通过在流中使用文件可以实现各种基本数据类型的的变量和引用数据类型的变量的数据在文件中存储。
ObjectInputStream:读取文件中存储的基本数据类型的的变量和引用数据类型的变量的数据,还原为基本数据类型的的变量和引用数据类型的变量,保存在内存中使用。
对象流中的方法:
对象流的方法也和数据流的相同,不过ObjectOutputStream多了一个void writeObjecct(Object obj),ObjectInputStream多了一个void readObject(Object obj)。
序列化机制:
序列化即把相应数据的信息转换为二进制流的信息以便于在硬盘或网络上存储。反序列化即把相应的二进制流的信息还原为相应数据的信息。
序列化过程使用的流:ObjectOutputStream流。将内存中的Java对象保存在文件中或通过网络传输出去。
例,要将一个String类型的对象存入指定文件中,操作如下:
java
void test1()
{
ObjectOutputStream oos = null;
try
{
//创建File的对象
File file = new File("object.txt");
oos = new ObjectOutputStream(new FileOutputStream(file));
//写出数据,即序列化的过程
String str = "jinitaimei";
oos.writeUTF(str);
} catch (IOException e)
{
e.printStackTrace();
} finally
{
//关闭资源
try
{
if (oos != null)
{
oos.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
}
}
反序列化过程使用的流:ObjectInputStream流。将文件中的数据或网络传输过来的数据还原为内存中的Java对象。
例,要将文件中存储的String类型的对象的数据还原为内存中的对象并将对象打印在控制台上,操作如下:
ini
void test2()
{
ObjectInputStream ois = null;
try
{
File file = new File("object.txt");
ois = new ObjectInputStream(new FileInputStream(file));
String str1 = ois.readUTF();
System.out.println(str1);
} catch (IOException e)
{
e.printStackTrace();
} finally
{
try
{
if (ois != null)
{
ois.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
}
}
自定义类实现序列化:
自定义类想要实现 序列化机制,需要满足:
①自定义类需要实现Serializable接口(Serializable属于一个标识接口)。
②要求自定义类声明一个全局常量:static final long serialVersionUID = (某个long类型的值,用来作为表示自定义类的唯一性的标识);
③要求自定义类的属性也必须是可序列化的。
·对于基本数据类型的属性:默认可序列化。
·对于引用数据类型的属性:相应的类要求实现Serializable接口,也要声明全局常量serialVersionUID,其中的属性也可序列化。
注意点:
①如果不声明全局常量serialVersionUID,系统会自动生成一个针对于当前类的serialVersionUID。如果对类修改之前存储了一个此类的对象在文件中或网络上(序列化),对类修改后,serialVersionUID的值也会变化,再要读取修改前读取的对象(反序列化),就会出现InvalidClassException异常。
②如果有某个属性不想序列化,在相应属性前加上transient关键字修饰,便不会被序列化。
③静态成员变量的值不会被序列化。因为静态成员变量的值不属于某个对象。