斜体样式## io流
数据在计算机中本质是二进制的字节流,所以在计算机中的操作都是以流的形式进行的。javaIO流,是一种计算机用语。主要是用于处理数据的传输。
io流图示:
1.字节流
1).OutputStream 字节输出流 (写入)
抽象类,无法直接使用,通过其子类FileOutputStream,向文件写入字节。
FileOutputStream 字节文件输出流
用于将数据写入到File,从程序中写入到其他位置。
public static void outputStreamMethod() throws IOException {
//指定文件所在的位置及名称
File file = new File("f:/io.txt");
//参数二:true代表接着文件的末尾续写
OutputStream os = new
FileOutputStream(file,true);
//写数字
os.write(18);
os.write(97);
//写字符串
os.write("haha".getBytes());
//关于流的操作,一定要有关闭流的动作
os.close();
}
2).InputStream 字节输入流(读取)
抽象类,无法直接使用,通过其子类FileInputStream,从文件中获取字节。
FileInputStream 字节文件输入流
从文件系统中的某个文件中获得输入字节,用于读取诸如图像数据之类的原始字节流。
public static void inputStreamMethod() throws IOException {
//指定文件所在的位置及名称
File file = new File("f:/io.txt");
InputStream is = new FileInputStream(file);
/*//每次读一个字节
int result = is.read();
System.out.println(result);*/
//使用数组读取时虽提高了操作效率,但会出现覆盖问题
byte[] bytes = new byte[4];
//read()方法返回-1到达流的末尾表示数据读取完成
while(is.read(bytes)!=-1) {
System.out.println(new String(bytes));
}
//关于流的操作,一定要有关闭流的动作
is.close();
}
总结:
字节流:
1.字节流在操作的时候不会用到缓冲区(也就是内存)
(没有关闭字节流操作,但是文件中也会依然存在了输出的内容,证明字节流是直接操作文件本身的)
2.字节流可用于任何类型的对象,包括二进制对象
3.字节流处理单元为1个字节,操作字节和字节数组。
InputStream是所有字节输入流的祖先,而OutputStream是所有字节输出流的祖先。
FileInputStream和FileOutputStream是操纵字节数据,当操纵字符数据时会有报错的可能,而且每次写入输出只是单个,所以并不能拿出来单独使用
2.字符流
字符流是由多个字节流组成,最小单位是b(字节)
1).Writer写入字符流的抽象类
抽象类,无法直接使用,通过其子类的子类FileWriter向文件写入字符。
FileWriter写入字符文件的方便类
public static void writerMethod() throws IOException {
Writer writer = new FileWriter("f:/writer.txt",true);
writer.write(98);
writer.write("李二");
writer.write("a");
//使用字符流在进行书写时要求刷新或关闭流
//writer.flush();
writer.write("张三");
//writer.flush();
writer.close();
//流关闭后不能再书写
//writer.write("李四");
}
2).Reader读取字符流的抽象类
抽象类,无法直接使用,通过其子类的子类FileReader从文件中获取字符。
FileReader读取字符文件的方便类
public static void readerMethod() throws IOException {
Reader reader = new FileReader("f:/writer.txt");
//每次读一个字节
/*int result = reader.read();
System.out.println((char)result);*/
//使用数组读取
char[] cbuf = new char[1024];
while(reader.read(cbuf)!=-1) {
System.out.println(new String(cbuf));
}
//关于流的操作,一定要有关闭流的动作
reader.close();
}
总结:
字符流:
1.字符流在操作的时候会用到缓冲区
(字符流不关闭执行后会发现文件中没有任何内容,这是因为字符流操作时使用了缓冲区,而 在关闭字符流时会强制性地将缓冲区中的内容进行输出,但是如果程序没有关闭,则缓冲区中的内容是无法输出的,所以得出结论:字符流使用了缓冲区,而字节流没有使用缓冲区。)
2.字符流只能处理字符或者字符串
3.字符流处理的单元为2个字节的Unicode字符,操作字符、字符数组或字符串,
Reader是所有读取字符串输入流的祖先,而writer是所有输出字符串的祖先
FileReader和FileWriter可以操纵字符数据,且文件的编码应该和Java所定的编码匹配,当遇到编码不符的情况,则会乱码。
3.流转换
字节流在读取的过程中效率高,针对某些问题(中文乱码,空间浪费等)不好处理,此时就需要将其转换字符流
字符流在读取的过程中效率低且有局限性(音频、视频等),此时就需要将其转换为字节流
针对上面的问题,我们使用了另外两种类,即InputStreamReader和OutputStreamWriter,这两种是Reader和Writer的子类,也是FIleReader和FileWriter 的父类。它们是字节到字符和字符到字节的桥梁,即可以将文件中的带有字符的字节数据顺利读入到Java中,将Java中的数据成功写入到文件中。在使用的过程中,我们需要指定编码,即文件和Java中指定的编码相匹配,这样编码相同了,字符也可以和字节互转了,我们可以成功的操纵数据了。
1).InputStreamReade是字节流通向字符流的桥梁
public static void main(String[] args) throws IOException {
//字节流-->字符流
//InputStream is = System.in;
//将字节输入流转换为字符输入流
//InputStreamReader isr = new InputStreamReader(is);
//将输入流包装一下--用缓冲流读
// BufferedReader br = new BufferedReader(isr);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new FileWriter("f:/is2.txt"));
String line = null;
while((line = br.readLine())!=null){
if("over".equals(line)){
break;
}
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
2).OutputStreamWriter是字符流通向字节流的桥梁
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("f:/is2.txt"));
//字符流-->字节流
//OutputStream os = System.out
//OutputStreamWrite osw= new OutputStreamWrite(os);
//BufferedWriter bw = new BufferedWrite(osw);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while ((line = br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
4.字符缓冲对象
可以简单地把缓冲区理解为一段特殊的内存。
某些情况下,如果一个程序频繁地操作一个资源(如文件或数据库),则性能会很低,此时为了提升性能,就可以将一部分数据暂时读入到内存的一块区域之中,以后直接从此区域中读取数据即可,因为读取内存速度会比较快,这样可以提升程序的性能。(高效率)
在字符流的操作中,所有的字符都是在内存中形成的,在输出前会将所有的内容暂时保存在内存之中,所以使用了缓冲区暂存数据。
如果想在不关闭时也可以将字符流的内容全部输出,则可以使用Writer类中的flush()方法完成。
1).BufferedWriter缓冲流对象写入
将文本写入到字符输出流中,缓冲字符,以便提供对单个字符、数组和字符串的有效写入。
public static void writerMethod() throws IOException {
Writer writer = new FileWriter("f:/buf.txt");
//创建缓冲流对象
BufferedWriter bw = new BufferedWriter(writer);
bw.write("生命在于运动1");
//输出换行符时要写\r\n
bw.write("\r\n");
bw.write("生命在于运动2");
//关闭流对象---倒着关
bw.close();
writer.close();
}
2).BufferedReader缓冲流对象读取
从一个字符输入流中读取文本,缓冲字符,以便提供字符、数组和行的有效读取。
public static void readerMethod() throws IOException {
Reader reader = new FileReader("f:/buf.txt");
//创建缓冲流对象
BufferedReader br = new BufferedReader(reader);
String str = null;
while((str=br.readLine())!=null) {
System.out.println(str);
}
//关闭流对象---倒着关
br.close();
reader.close();
}
5.字符串缓冲对象
StringBuffer字符串缓冲区对象
特点:线程安全的可变字符串。同步,效率低
StringBuffer类和String一样,也用来代表字符串,只是由于StringBuffer的内部实现方式和String不同,所以StringBuffer在进行字符串处理时,不生成新的对象,在内存使用上要优于String类。
所以在实际使用时,如果经常需要对一个字符串进行修改,例如插入、删除等操作,使用StringBuffer要更加适合一些。
在StringBuffer类中存在很多和String类一样的方法,这些方法在功能上和String类中的功能是完全一样的。
但是有一个最显著的区别在于,对于StringBuffer对象的每次修改都会改变对象自身,这点是和String类最大的区别。
另外由于StringBuffer是线程安全的,所以在多线程程序中也可以很方便的进行使用,但是程序的执行效率相对来说就要稍微慢一些。
public static void readerMethod3() throws IOException {
Reader reader = new FileReader("f:/buf.txt");
char[] cbuf = new char[1024];
//定义一个字符串缓冲对象用于接收字符串
StringBuilder sb = new StringBuilder();
while(reader.read(cbuf)!=-1) {
//添加到字符串缓冲区里面,并返回字符串缓冲区本身
sb.append(cbuf);
}
System.out.println(sb.toString());
//关闭流对象
reader.close();
}
6.流写对象
通过流的形式将自定义对象写到指定的文件中,该形式称为持久化存储(数据本地存储)
/**
* 写对象
* @throws IOException
*/
public static void writeObject() throws IOException {
User user = new User(12,"哈哈");
//获取对象的输出流--写对象
OutputStream os = new FileOutputStream("f:/object.txt");
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(user);
//关闭流对象
oos.close();
os.close();
}
运行后出现错误:实例对象未序列化异常
序列化:其实就是为要写的对象一个标识符,在java中对应将对象转成流的形式写入到指定文件中
反序列化:根据标识符再进行匹配,通过指定文件以流的形式读取到的结果再包装成对象
使用方式:只需要实体类实现一个名叫Serializable接口即可
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private int age;
private String name;
private static int count;
//transient修饰的变量称为瞬态变量
private transient int num;
private String address;
public User(int age,String name) {
this.age = age;
this.name = name;
}
public void show() {}
@Override
public String toString() {
return "User [age=" + age + ", name=" + name + ", address=" + address + "]";
}
}
反序列化:读取过程中
/**
* 读取对象
* @throws IOException
* @throws ClassNotFoundException
*/
public static void readerObject() throws IOException, ClassNotFoundException {
InputStream is = new FileInputStream("f:/object.txt");
ObjectInputStream ois = new ObjectInputStream(is);
//读对象
Object obj = ois.readObject();
//强制类型转换
User user = (User)obj;
System.out.println(user);
//关闭流
ois.close();
is.close();
}
如果实体类中未指定seriaVersionId,那么在持久化存储后,一旦实体类做了修改,那么反序列化时就会报错