标签:auto ted import 导入 文字 文件路径 har font name
在学习字符流(FileReader、FileWriter)的时候,其中说如果需要指定编码和缓冲区大小时,可以在字节流的基础上,构造一个InputStreamReader或者OutputStreamWriter,这又是什么意思呢?
查阅OutputStreamWriter的API介绍,OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的字符编码表,将要写入流中的字符编码成字节。它的作用的就是,将字符串按照指定的编码表转成字节,再使用字节流将这些字节写出去。
代码演示:
public static void writeCN() throws Exception { //创建与文件关联的字节输出流对象 FileOutputStream fos = new FileOutputStream("D:\\cn8.txt"); //创建可以把字符转成字节的转换流对象,并指定编码 OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8"); //调用转换流,把文字写出去,其实是写到转换流的缓冲区中 osw.write("你好");//写入缓冲区。 osw.close(); }
OutputStreamWriter流对象,它到底如何把字符转成字节输出的呢?
其实在OutputStreamWriter流中维护自己的缓冲区,当我们调用OutputStreamWriter对象的write方法时,会拿着字符到指定的码表中进行查询,把查到的字符编码值转成字节数存放到OutputStreamWriter缓冲区中。然后再调用刷新功能,或者关闭流,或者缓冲区存满后会把缓冲区中的字节数据使用字节流写到指定的文件中。
查阅InputStreamReader的API介绍,InputStreamReader 是字节流通向字符流的桥梁:它使用指定的字符编码表读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
代码演示
package io; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; /** * Created by Administrator on 2017/7/19. */ public class InputStreamReaderDemo { public static void main(String[] args) throws IOException { //演示字节转字符流的转换流 readCN(); } public static void readCN() throws IOException { //创建读取文件的字节流对象 InputStream in = new FileInputStream("d:\\cn8.txt"); //创建转换流对象 //InputStreamReader isr = new InputStreamReader(in);这样创建对象,会用本地默认码表读取,将会发生错误解码的错误 InputStreamReader isr = new InputStreamReader(in, "utf-8"); //使用转换流去读字节流中的字节 int ch = 0; while ((ch = isr.read()) != -1) { System.out.println((char) ch); } //关闭流 isr.close(); } }
注意:在读取指定的编码的文件时,一定要指定编码格式,否则就会发生解码错误,而发生乱码现象。
发现有如下继承关系:
OutputStreamWriter |--FileWriter InputStreamReader |--FileReader;
父类和子类的功能有什么区别呢?
OutputStreamWriter和InputStreamReader是字符和字节的桥梁:也可以称之为字符转换流。字符转换流原理:字节流+编码表。
FileWriter和FileReader:作为子类,仅作为操作字符文件的便捷类存在。当操作的字符文件,使用的是默认编码表时可以不用父类,而直接用子类就完成操作了,简化了代码。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默认字符集。 InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。 FileReader fr = new FileReader("a.txt");
这三句代码的功能是一样的,其中第三句最为便捷。注意:一旦要指定其他编码时,绝对不能用子类,必须使用字符转换流。什么时候用子类呢?
条件:1、操作的是文件。2、使用默认编码。
字节--->字符 : 看不懂的--->看的懂的。 需要读。输入流。 InputStreamReader
字符--->字节 : 看的懂的--->看不懂的。 需要写。输出流。 OutputStreamWriter
在我们学习字节流与字符流的时候,大家都进行过读取文件中数据的操作,读取数据量大的文件时,读取的速度会很慢,很影响我们程序的效率,那么,我想提高速度,怎么办?
Java中提高了一套缓冲流,它的存在,可提高IO流的读写速度。缓冲流,根据流的分类,分为字节缓冲流与字符缓冲流。
字节缓冲流根据流的方向,共有2个
它们的内部都包含了一个缓冲区,通过缓冲区读写,就可以提高了IO流的读写速度
通过字节缓冲流,进行文件的读写操作 写数据到文件的操作
构造方法
public BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
package io; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; /** * Created by Administrator on 2017/7/19. */ public class BufferedOutputStreamDemo01 { public static void main(String[] args) throws IOException { //写数据到文件的方法 write(); } /* * 写数据到文件的方法 * 1,创建流 * 2,写数据 * 3,关闭流 */ private static void write() throws IOException { //创建基本的字节输出流 FileOutputStream fileOut = new FileOutputStream("abc.txt"); //使用高效的流,把基本的流进行封装,实现速度的提升 BufferedOutputStream out = new BufferedOutputStream(fileOut); //2,写数据 out.write("hello".getBytes()); //3,关闭流 out.close(); } }
刚刚我们学习了输出流实现了向文件中写数据的操作,那么,现在我们完成读取文件中数据的操作
构造方法
public BufferedInputStream(InputStream in)
/* 从文件中读取数据 * 1,创建缓冲流对象 * 2,读数据,打印 * 3,关闭 */ private static void read() throws IOException { //1,创建缓冲流对象 FileInputStream fileIn = new FileInputStream("abc.txt"); //把基本的流包装成高效的流 BufferedInputStream in = new BufferedInputStream(fileIn); //2,读数据 int ch = -1; while ((ch = in.read()) != -1) { //打印 System.out.print((char) ch); } //3,关闭 in.close(); }
我们一直在说,高效的流速度快并高效,怎么体现呢?需要通过一个复制文件耗时的比较过程,来体验一下高效流带来的快感。
package io; /* * 需求:将d:\\test.avi文件进行复制 * 采用4种方式复制 * 方式1: 采用基本的流,一次一个字节的方式复制 共耗时 224613毫秒 * 方式2: 采用基本的流,一个多个字节的方式赋值 共耗时 327毫秒 * 方式3: 采用高效的流,一次一个字节的方式复制 共耗时 2047毫秒 * 方式4: 采用高效的流,一个多个字节的方式赋值 共耗时 96毫秒 * * 数据源: d:\\test.avi * 目的地1: d:\\copy1.avi * 目的地2: d:\\copy2.avi * 目的地3: d:\\copy3.avi * 目的地4: d:\\copy4.avi * * 实现的步骤: * 1,指定数据源 * 2,指定目的地 * 3,读数据 * 4,写数据 * 5,关闭流 * */ import java.io.*; public class CopyAVI { public static void main(String[] args) throws IOException { //开始计时 long start = System.currentTimeMillis(); //方式1: 采用基本的流,一次一个字节的方式复制 //method1("d:\\test.avi", "d:\\copy1.avi"); //方式2: 采用基本的流,一个多个字节的方式赋值 //method2("d:\\test.avi", "d:\\copy2.avi"); //方式3: 采用高效的流,一次一个字节的方式复制 //method3("d:\\test.avi", "d:\\copy3.avi"); //方式4: 采用高效的流,一个多个字节的方式赋值 method4("d:\\test.avi", "d:\\copy4.avi"); //结束计时 long end = System.currentTimeMillis(); //打印耗时多少毫秒 System.out.println("共耗时 " +(end - start)+ "毫秒"); } //方式4: 采用高效的流,一个多个字节的方式赋值 private static void method4(String src, String dest) throws IOException { //1,指定数据源 BufferedInputStream in = new BufferedInputStream(new FileInputStream(src)); //2,指定目的地 BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest)); //3,读数据 byte[] buffer = new byte[1024]; int len = -1; while ( (len = in.read(buffer)) != -1) { //4,写数据 out.write(buffer, 0, len); } //5,关闭流 in.close(); out.close(); } //方式3: 采用高效的流,一次一个字节的方式复制 private static void method3(String src, String dest) throws IOException { //1,指定数据源 BufferedInputStream in = new BufferedInputStream(new FileInputStream(src)); //2,指定目的地 BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest)); //3,读数据 int ch = -1; while ((ch=in.read()) != -1) { //4,写数据 out.write(ch); } //5,关闭流 in.close(); out.close(); } //方式2: 采用基本的流,一个多个字节的方式赋值 private static void method2(String src, String dest) throws IOException { //1,指定数据源 FileInputStream in = new FileInputStream(src); //2,指定目的地 FileOutputStream out = new FileOutputStream(dest); //3,读数据 byte[] buffer = new byte[1024]; int len = -1; while ( (len=in.read(buffer)) != -1) { //4,写数据 out.write(buffer, 0, len); } //5,关闭流 in.close(); out.close(); } //方式1: 采用基本的流,一次一个字节的方式复制 private static void method1(String src, String dest) throws IOException { //1,指定数据源 FileInputStream in = new FileInputStream(src); //2,指定目的地 FileOutputStream out = new FileOutputStream(dest); //3,读数据 int ch = -1; while (( ch=in.read()) != -1) { //4,写数据 out.write(ch); } //5,关闭流 in.close(); out.close(); } }
完成文本数据的高效的写入与读取的操作
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
方法:void newLine() 根据当前的系统,写入一个换行符
package io; /* * BufferedWriter 字符缓冲输出流 * 方法 * public void newLine()写入一个行分隔符 * * 需求: 通过缓冲输出流写入数据到文件 * 分析: * 1,创建流对象 * 2,写数据 * 3,关闭流 * */ import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class BufferedWriterDemo { public static void main(String[] args) throws IOException { //创建流 //基本字符输出流 FileWriter fileOut = new FileWriter("file.txt"); //把基本的流进行包装 BufferedWriter out = new BufferedWriter(fileOut); //2,写数据 for (int i=0; i<5; i++) { out.write("hello"); out.newLine(); } //3,关闭流 out.close(); } }
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
方法 :public String readLine() 读取一个文本行,包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
package io; /* * BufferedReader 字符缓冲输入流 * * 方法: * String readLine() * 需求:从文件中读取数据,并显示数据 */ import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class BufferedReaderDemo { public static void main(String[] args) throws IOException { //1,创建流 BufferedReader in = new BufferedReader(new FileReader("file.txt")); //2,读数据 //一次一个字符 //一次一个字符数组 //一次读取文本中一行的字符串内容 String line = null; while( (line = in.readLine()) != null ){ System.out.println(line); } //3,关闭流 in.close(); } }
刚刚我们学习完了缓冲流,现在我们就使用字符缓冲流的特有功能,完成文本文件的复制
package io; /* * 采用高效的字符缓冲流,完成文本文件的赋值 * * 数据源: file.txt * 目的地: copyFile.txt * * 分析: * 1,指定数据源, 是数据源中读数据,采用输入流 * 2,指定目的地,是把数据写入目的地,采用输出流 * 3,读数据 * 4,写数据 * 5,关闭流 */ import java.io.*; public class CopyTextFile { public static void main(String[] args) throws IOException { //1,指定数据源, 是数据源中读数据,采用输入流 BufferedReader in = new BufferedReader(new FileReader("file.txt")); //2,指定目的地,是把数据写入目的地,采用输出流 BufferedWriter out = new BufferedWriter(new FileWriter("copyFile.txt")); //3,读数据 String line = null; while ( (line = in.readLine()) != null ) { //4,写数据 out.write(line); //写入换行符号 out.newLine(); } //5,关闭流 out.close(); in.close(); } }
IO流中对象很多,解决问题(处理设备上的数据时)到底该用哪个对象呢?
把IO流进行了规律的总结(四个明确):
先根据需求明确要读,还是要写。
源:
目的:
已经明确到了具体的体系上。
源设备:
目的设备:
完全可以明确具体要使用哪个流对象。
额外功能:
InputStream
FileInputStream
BufferedInputStream
OuputStream
FileOutputStream
BufferedOuputStream
Writer
OutputStreamWriter
FileWriter
BufferedWriter
Reader
InputStreamReader
FileReader
BufferedReader
字节输入流 InputStream
字节输出流 OutputStream
字符输入流 Reader
字符输出流 Writer
读数据方法:
写数据方法:
Properties类表示了一个持久的属性集。Properties可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
特点:
load(InputStream) 把指定流所对应的文件中的数据,读取出来,保存到Propertie集合中
load(Reader)
store(OutputStream,commonts)把集合中的数据,保存到指定的流所对应的文件中,参数commonts代表对描述信息
stroe(Writer,comments);
代码演示:
package io; import java.util.Properties; import java.util.Set; /* * * Properties集合,它是唯一一个能与IO流交互的集合 * * 需求:向Properties集合中添加元素,并遍历 * * 方法: * public Object setProperty(String key, String value)调用 Hashtable 的方法 put。 * public Set<String> stringPropertyNames()返回此属性列表中的键集, * public String getProperty(String key)用指定的键在此属性列表中搜索属性 */ public class PropertiesDemo01 { public static void main(String[] args) { //创建集合对象 Properties prop = new Properties(); //添加元素到集合 //prop.put(key, value); prop.setProperty("周迅", "张学友"); prop.setProperty("李小璐", "贾乃亮"); prop.setProperty("杨幂", "刘恺威"); //System.out.println(prop);//测试的使用 //遍历集合 Set<String> keys = prop.stringPropertyNames(); for (String key : keys) { //通过键 找值 //prop.get(key) String value = prop.getProperty(key); System.out.println(key+"==" +value); } } }
package io; import java.io.FileWriter; import java.io.IOException; import java.util.Properties; //需求:使用Properties集合,完成把集合内容存储到IO流所对应文件中的操作 //分析: //1,创建Properties集合 //2,添加元素到集合 //3,创建流 //4,把集合中的数据存储到流所对应的文件中 //stroe(Writer,comments) //store(OutputStream,commonts) //把集合中的数据,保存到指定的流所对应的文件中,参数commonts代表对描述信息 //5,关闭流 // //代码演示: public class PropertiesDemo02 { public static void main(String[] args) throws IOException { //1,创建Properties集合 Properties prop = new Properties(); //2,添加元素到集合 prop.setProperty("周迅", "张学友"); prop.setProperty("李小璐", "贾乃亮"); prop.setProperty("杨幂", "刘恺威"); //3,创建流 FileWriter out = new FileWriter("prop.properties"); //4,把集合中的数据存储到流所对应的文件中 prop.store(out, "save data"); //5,关闭流 out.close(); } }
package io; import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; //需求:从属性集文件prop.properties 中取出数据,保存到集合中 // 分析: // 1,创建集合 // 2,创建流对象 // 3,把流所对应文件中的数据 读取到集合中 // load(InputStream) 把指定流所对应的文件中的数据,读取出来,保存到Propertie集合中 // load(Reader) // 4,关闭流 // 5,显示集合中的数据 // 代码演示: public class PropertiesDemo03 { public static void main(String[] args) throws IOException { //1,创建集合 Properties prop = new Properties(); //2,创建流对象 FileInputStream in = new FileInputStream("prop.properties"); //FileReader in = new FileReader("prop.properties"); //3,把流所对应文件中的数据 读取到集合中 prop.load(in); //4,关闭流 in.close(); //5,显示集合中的数据 System.out.println(prop); } }
注意:使用字符流FileReader就可以完成文件中的中文读取操作了。
用于从流中读取对象的操作流 ObjectInputStream 称为 反序列化流;用于向流中写入对象的操作流 ObjectOutputStream 称为 序列化流
特点:用于操作对象。可以将对象写入到文件中,也可以从文件中读取对象。
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。
代码演示:
package io; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class ObjectStreamDemo { public static void main(String[] args) throws IOException, ClassNotFoundException { /* * 将一个对象存储到持久化(硬盘)的设备上。 */ writeObj();//对象的序列化。 } public static void writeObj() throws IOException { //1,明确存储对象的文件。 FileOutputStream fos = new FileOutputStream("obj.object"); //2,给操作文件对象加入写入对象功能。 ObjectOutputStream oos = new ObjectOutputStream(fos); //3,调用了写入对象的方法。 oos.writeObject(new Person("wangcai",20)); //关闭资源。 oos.close(); } }
Person类
package io; import java.io.Serializable; public class Person implements Serializable { private String name; private int age; public Person() { super(); } public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。支持 java.io.Serializable接口的对象才能从流读取。
代码演示:
package io; import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class ObjectStreamDemo1 { public static void main(String[] args) throws IOException, ClassNotFoundException { readObj();//对象的反序列化。 } public static void readObj() throws IOException, ClassNotFoundException { //1,定义流对象关联存储了对象文件。 FileInputStream fis = new FileInputStream("obj.object"); //2,建立用于读取对象的功能对象。 ObjectInputStream ois = new ObjectInputStream(fis); Person obj = (Person)ois.readObject(); System.out.println(obj.toString()); } }
当一个对象要能被序列化,这个对象所属的类必须实现Serializable接口。否则会发生异常NotSerializableException异常。
同时当反序列化对象时,如果对象所属的class文件在序列化之后进行的修改,那么进行反序列化也会发生异常InvalidClassException。发生这个异常的原因如下:
Serializable标记接口。该接口给需要序列化的类,提供了一个序列版本号。serialVersionUID. 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
代码修改如下,修改后再次写入对象,读取对象测试。
public class Person implements Serializable { //给类显示声明一个序列版本号。 private static final long serialVersionUID = 1L; private String name; private int age; public Person() { super(); } public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
当一个类的对象需要被序列化时,某些属性不需要被序列化,这时不需要序列化的属性可以使用关键字transient修饰。只要被transient修饰了,序列化时这个属性就不会被序列化了。
同时静态修饰也不会被序列化,因为序列化是把对象数据进行持久化存储,而静态的属于类加载时的数据,不会被序列化。
代码修改如下,修改后再次写入对象,读取对象测试。
public class Person implements Serializable { /* * 给类显示声明一个序列版本号。 */ private static final long serialVersionUID = 1L; private static String name; private transient/*瞬态*/ int age; public Person() { super(); } public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
打印流添加输出数据的功能,使它们能够方便地打印各种数据值表示形式.
打印流根据流的分类:
方法:
package io; import java.io.IOException; import java.io.PrintWriter; /* * 需求:把指定的数据,写入到printFile.txt文件中 * * 分析: * 1,创建流 * 2,写数据 * 3,关闭流 */ public class PrintWriterDemo { public static void main(String[] args) throws IOException { //创建流 //PrintWriter out = new PrintWriter(new FileWriter("printFile.txt")); PrintWriter out = new PrintWriter("printFile.txt"); //2,写数据 for (int i=0; i<5; i++) { out.println("helloWorld"); } //3,关闭流 out.close(); } }
可以通过构造方法,完成文件数据的自动刷新功能
构造方法:开启文件自动刷新写入功能
package io; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; /* * 分析: * 1,创建流 * 2,写数据 */ public class PrintWriterDemo2 { public static void main(String[] args) throws IOException { //创建流 PrintWriter out = new PrintWriter(new FileWriter("printFile.txt"), true); //2,写数据 for (int i=0; i<5; i++) { out.println("helloWorld"); } //3,关闭流 out.close(); } }
1、导入classpath
2、FilenameUtils
这个工具类是用来处理文件名(译者注:包含文件路径)的,他可以轻松解决不同操作系统文件名称规范不同的问题
常用方法:
3、FileUtils
提供文件操作(移动文件,读取文件,检查文件是否存在等等)的方法。
常用方法:
代码演示:
package io; import org.apache.commons.io.FileUtils; import java.io.*; /* * 完成文件的复制 */ public class CommonsIODemo01 { public static void main(String[] args) throws IOException { //method1("D:\\test.avi", "D:\\copy.avi"); //通过Commons-IO完成了文件复制的功能 FileUtils.copyFile(new File("D:\\test.avi"), new File("D:\\copy.avi")); //通过Commons-IO完成了文件夹复制的功能 //D:\java 复制到 C:\\abc文件夹下 FileUtils.copyDirectoryToDirectory(new File("D:\\java"), new File("C:\\abc")); } }
标签:auto ted import 导入 文字 文件路径 har font name
原文地址:http://www.cnblogs.com/ginb/p/7207076.html