IO流
一、文件
文件,保存数据的地方;
如:.txt .mp4 .jpg .png等等
在java中,目录也被当做文件
文件流,文件在程序中是以流的形式来操作的;
流:数据在数据源(文件)和程序(内存)之间经历的路径;
输入流:数据从数据源(文件)到程序(内存)的路径;
输出流:数据从程序(内存)到数据源(文件)的路径;
二、常见的文件操作
文件对象创建的三种不同方式,但只是创建对象,之后调用createNewFile()方法,才是真正地在内存成功创建文件。
new File(String pathname) //根据路径构建一个File对象
new File(File parent,String child) //根据父目录文件+子路径构建
new File(String parent,String child) //根据父目录+子路径构建
例:
public void createFile3(){
String parentName="D:\\";
String fileName="a3.txt";
File file = new File(parentName,fileName);//这里是file对象,在java程序中,只是一个对象
try {
file.createNewFile(); //只有执行了这个动作,这个文件才会产生
} catch (IOException e) { // 之前的东西都是在内存中
throw new RuntimeException(e);
}
}
@Test
public void createFile2(){
File parentfile = new File("D:\\");
String filename="a2.txt";
File file = new File(parentfile,filename);
try {
file.createNewFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Test
public void createFile3(){
String parentName="D:\\";
String fileName="a3.txt";
File f = new File(parentName,fileName);
try {
f.createNewFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
获取文件的相关信息
file.getName() //名字
file.getAbsolutePath() //绝对路径
file.getParent() //父级目录
file.length() //大小(字节)
file.exists() //判断文件是否存在(目录也是文件)
file.isFile()
file.isDirectory()
@Test
public void info(){
File file = new File("D:\\aa");
System.out.println(file.getAbsolutePath());
System.out.println(file.getName());
System.out.println(file.getParent());
System.out.println(file.isDirectory());
System.out.println(file.isFile());
}
Java中的file同样也是一个类
常见的文件操作
file.mkdir() //创建一级目录
file.mkdirs() //创建多级目录
file.delete() //删除空目录或文件
public void test1(){
File file = new File("D:\\aa");
if (file.exists()){
System.out.println("该文件存在");
file.delete();
System.out.println("删除成功");
}
else{
System.out.println("该文件不存在");
}
}
三、IO流原理与流的分类
Java IO流原理
I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理数据传输。
Java程序中,对于数据的输入/输出操作是以“流(stream)”的形式操作的;
java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过方法输入或输出数据。
输入流,输出流
流的分类
按操作数据单位不同分为:
字节流(8 bit)适合二进制文件;
字符流(按字符,根据编码的不同,大小也不同)适合文本文件
按数据流的流向不同分为:输入流,输出流
按流的角色的不同分为:节点流,处理流/包装流
按节点流,操作数据,和流向细分为
字节流中的输入流,顶级父类InputStream //抽象类
字节流中的输出流,顶级父类OutputStream //抽象类
字符流中的输入流,顶级父类Reader //抽象类
字符流中的输出流,顶级父类Writer //抽象类
Java的IO流共涉及40多个类,都是从上面的4个抽象基类派生的。
四、IO流中,常用的类
InputStream 常用的类
FileInputStream //文件输入流
BufferedInputStream //缓冲字节输入流
ObjectInputStream //对象字节输入流
当流的对象和文件关联起来后,我们就可以用这个流对象操作这个文件;
new FileInputStream(filename)
new FileInputStream(file) //等等,根据不同的构造器都可以创建
创建这些类的对象,就可以对这个文件进行操作,读取read()
直接用read()读取,每次只会读取一个字节的信息;
也可以用字节数组来读取,如下:
byte[] buf = new byte[8];
int readlen=0;
readlen=fileInputStream.read(buf) ,返回的是实际读取的字节数(结束是readlen==-1)
System.out.print(new String (buf,0,readlen));
OutputStream 常用类
FileOutputStream
new FileOutputStream(filename) //创建对象,覆盖原来的内容,(只有再次创建且写入的时候才会覆盖,如果是新文件,就没事了,原来的内容没有东西)
new FileOutputStream(filename,true)//创建对象,写入的内容,是追加到文件后面的
write('a')方法,将指定的字节,写入此文件输出流,如果文件不存在,会按照路径自动创建,并写入;
write(byte[]); write(str.getBytes()); //将字符串转换为byte数组
write(byte[],begin,len); //写入从begin开始,偏移len长度的字节数组
@Test
public void info1(){
String filename="D:\\Date\\笔记.txt";//文件路径
File file = new File(filename);
FileReader fileReader=null;
try {
fileReader=new FileReader(file); //创建流对象,关联文件
int read=0;
while ((read=fileReader.read())!=-1){
System.out.print((char)read); //读取文件内容
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
fileReader.close(); //关闭流对象并释放相关资源
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Test
public void put(){
String filename="D:\\Date\\aaa.txt";
FileOutputStream fileOutputStream=null;
try {
fileOutputStream= new FileOutputStream(filename);
fileOutputStream.write("adfasf".getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Test
public void t(){
String filePath="C:\\Users\\OLDERHARD\\Pictures\\preview.jpg";
FileInputStream fileInputStream=null;
FileOutputStream fileOutputStream=null;
try {
fileInputStream = new FileInputStream(filePath);
fileOutputStream=new FileOutputStream("D:\\untitled1\\src\\copy.jpg",true );
byte[] bytes = new byte[1024];
int len=0;
while ((len=fileInputStream.read(bytes))!=-1){
fileOutputStream.write(bytes,0,len);
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
if (fileInputStream!=null){
try {
fileInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (fileOutputStream!=null){
try {
fileOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
FileReader 和 FileWriter
FileReader 和 FileWriter 是字符流,即按照字符来操作IO
FileReader(字符输入流) 的相关方法
new FileReader(File/String);
read() //每次读取单个字符,返回该字符,到文件末尾返回-1;
read(char[]) //批量读入字符到数组中,返回读到的字符数,到文件末尾返回-1;
new String(char[]); //将字符串转换为字符数组
new String(char[],begin,len); //写入从begin开始,偏移len长度的字符数组
FileWriter(字符输出流) 的相关方法
new FileWriter(File/String); //会覆盖文件,流的指针在首端
new FileWriter(File/String,true); //追加模式,不会覆盖
write(int); //写入单个字符
write(char[]); //写入指定数组
write(char[],begin,len); //写入指定数组的指定部分
write(String); //写入整个字符串
write(String,begin,len); //写入字符串的指定部分
FileWriter使用后,必须要关闭(close)或刷新(flush),否则写入不到指定文件!
@Test
public void fileread1(){
FileReader fileReader=null;
String filePath="D:\\Date\\aaa.txt";
try {
FileReader fileReader1 = new FileReader(filePath);
int len=0;
char[] chars = new char[1024];
while ((len=fileReader1.read(chars))!=-1){
System.out.print(new String(chars,0,len));
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
if (fileReader!=null){
try {
fileReader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
@Test
public void copy1(){
String filePath="D:\\Date\\aaa.txt";
String filePath1="D:\\Date\\bbb.txt";
FileReader fileReader=null;
FileWriter fileWriter=null;
try {
fileReader = new FileReader(filePath);
fileWriter = new FileWriter(filePath1);
int len=0;
char[] chars = new char[1024];
while ((len=fileReader.read(chars))!=-1){
fileWriter.write(chars,0,len);
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
if (fileReader!=null){
try {
fileReader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (fileWriter!=null){
try {
fileWriter.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
总的来说,创建文件的输入流,将文件读入到程序;创建文件的输出流,将读取到的文件数据,写到指定的文件;
当两者在一起工作时,会用到while循环,程序会从输入流的文件读取部分数据,再将这部分数据写到输出流的文件处,直到结束。
五,节点流和处理流
节点流:可以从特定的数据源读取数据,如访问文件,数组,管道,字符串等,如FileReader,FileWriter,FileInputStream等;
节点流是底层流,直接跟数据源相接。
处理流(包装流):对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连,使得节点流的功能更加强大,也更加灵活。可以理解为在处理流的类里有如Reader,Writer的属性,当调用处理流的时候,能处理 正常Reader,Writer能处理的数据源。
处理流的功能体现:
1.性能的提高:主要以增强缓冲的方式来提高输入输出效率;
2.操作的便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便;
六、常见的处理流
1.BufferedRead和BufferedWriter
BufferedRead和BufferedWriter属于字符流,按字符读取数据。关闭时,只需要关闭外层流即可。
底层其实调用的节点流,BufferedRead提供了一些其他的read方法,如readLine(),newLine()。
@Test
public void bufferedRead(){
String filePath="D:\\Date\\aaa.txt";
BufferedReader bufferedReader = null;
try {
bufferedReader =new BufferedReader(new FileReader(filePath)); //实际上,底层调用还是 FileReader
String read=null;
while ((read=bufferedReader.readLine())!=null){ //可以按行读取,末尾返回null
System.out.println(read);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (bufferedReader!=null){
try {
bufferedReader.close(); //关闭外层流即可,底层会自动关闭节点流的。
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
@Test
public void copy(){
String filePath="D:\\Date\\aaa.txt";
String filePath1="D:\\Date\\ccc.txt";
BufferedReader bufferedReader=null;
BufferedWriter bufferedWriter=null;
try {
bufferedReader=new BufferedReader(new FileReader(filePath));
bufferedWriter=new BufferedWriter(new FileWriter(filePath1));
String read=null;
while ((read=bufferedReader.readLine())!=null){
bufferedWriter.write(read);
bufferedWriter.newLine(); //得自己添加换行,它被“吃”了
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (bufferedReader!=null){
try {
bufferedReader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (bufferedWriter!=null){
try {
bufferedWriter.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
2.BufferedInputStream和BufferedOutputStream
BufferedInputStream和BufferedOutputStream属于字节流,按按字节读取。同样,关闭时只需要关闭外层流即可。
底层其实调用的节点流,方法跟前面的一样,没有增加的方法。
@Test
public void bufferedCopy(){
String filePath="C:\\Users\\OLDERHARD\\Pictures\\preview.jpg";
String filePath1="D:\\Date\\preview.jpg";
BufferedInputStream bufferedInputStream=null;
BufferedOutputStream bufferedOutputStream=null;
try {
bufferedInputStream=new BufferedInputStream(new FileInputStream(filePath));
bufferedOutputStream=new BufferedOutputStream(new FileOutputStream(filePath1));
int len=0;
byte[] bytes = new byte[1024];
while ((len=bufferedInputStream.read(bytes))!=-1){
bufferedOutputStream.write(bytes,0,len);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if (bufferedInputStream!=null){
bufferedInputStream.close();
}
if (bufferedOutputStream!=null){
bufferedOutputStream.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
3.ObjectInputStream 和 ObjectOutputStream (对象流)
保存数据,并且保存它的数据类型,就是能够将基本数据类型或者对象进行序列化和反序列化操作。
也就是write时要将数据的值和数据类型写入,read时要将数据的的值和数据类型复原。
当然前提是你操作的数据能够被序列化。要让一个对象支持序列化机制,它的类得是可序列化的,那这个类就得实现这两个接口之一 Serializable、Externalizable.
Serializable,是个标记接口,意思是这个接口里面没有方法,空的,一般推荐使用;
基本数据类型都有它的包装类,如Integer,Double等等,这些包装类都实现了Serializable,又因为自动装箱机制,所有基本数据类型,直接写入即可。
String同样自己实现了Serializable接口;
关于自定义的类,就得自己实现Serializable接口了。
关于读取,读取(反序列化)的顺序需要和保存数据(序列化)要一致。
要想读取自定义类的详细信息,得将自定义类拷贝到引用的位置,否则就算向下转型,还是访问不了。
@Test
public void ObjectWrite(){
String filePath="D:\\Date\\ccc.dat";
ObjectOutputStream objectOutputStream=null;
try {
objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));
objectOutputStream.writeInt(100);
objectOutputStream.writeDouble(100.0);
objectOutputStream.writeChar('a');
objectOutputStream.writeUTF("zaijian");
objectOutputStream.writeObject(new person("olderhard",22));
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (objectOutputStream!=null){
try {
objectOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
@Test
public void objectRead(){
String filePath="D:\\Date\\ccc.dat";
ObjectInputStream objectInputStream=null;
try {
objectInputStream = new ObjectInputStream(new FileInputStream(filePath));
System.out.println(objectInputStream.readInt());
System.out.println(objectInputStream.readDouble());
System.out.println(objectInputStream.readChar());
System.out.println(objectInputStream.readUTF());
person person=null;
try {
person=(person) objectInputStream.readObject();
System.out.println(person);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (objectInputStream!=null){
try {
objectInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
class person implements Serializable {
private String name;
private int age;
public person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
4.标准输入流和标准输出流
System.in,编译类型IntputStream,运行类型BufferedIntputStream (标准输入,键盘)
System.out ,编译类型PrintStream,运行类型PrintStream (标准输出,显示器)
5.转换流 InputStreamReader 和 OutputStreamWriter
把一种字节流转换为字符流,就是在字节流的基础上可以指定特定的编码方式如,utf-8,gbk等,转换为字符流;
注意,就是一种包装。
InputStreamReader将InputStream包装成Reader
OutputStreamWriter将OutputStream包装成Writer
@Test
public void outputStreamWriter(){
String filePath="D:\\Date\\ddd.dat";
BufferedWriter bufferedWriter=null;
try {
bufferedWriter= new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath),"gbk"));
bufferedWriter.write("再见再也不见");
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (bufferedWriter!=null){
try {
bufferedWriter.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
@Test
public void inputStreamReader(){
String filePath="D:\\Date\\ddd.dat";
BufferedReader bufferedReader=null;
try {
InputStreamReader inputStreamReader =new InputStreamReader(new FileInputStream(filePath),"gbk");
//将FileInputStream包装了一下,再用bufferdReader流
bufferedReader = new BufferedReader(inputStreamReader);
String read=null;
while ((read=bufferedReader.readLine())!=null){
System.out.println(read);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (bufferedReader!=null){
try {
bufferedReader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
6.打印流 PrintStream 和 PrintWriter (只有输出流)
@Test
public void printStream(){
PrintStream printStream=System.out;
//默认情况下,是标准输出
printStream.print("再见,再也不见");
try {
System.setOut(new PrintStream("D:\\Date\\eee.txt"));
printStream=System.out;
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
printStream.print("zaijian");
// System.out.print("zaijian");
printStream.close();
}
@Test
public void printWriter(){
String filePath="D:\\Date\\fff.txt";
PrintWriter printWriter=null;
try {
//printWriter = new PrintWriter(new FileWriter(filePath,true));
printWriter= new PrintWriter(System.out);
printWriter.println("再见,再也不见");
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (printWriter!=null){
printWriter.close();
}
}
}
七、Properties类
专门用于读写配置文件的集合类
配置文件格式:
键=值
键=值
键和值,都默认是String,不需要用引号
Properties常见方法
load,加载配置文件的键值对到Properties对象
list,将数据显示到指定设备,可以是流对象,文件,显示器
getProperty(key),根据键获取值
setProperty(key,value),设置键值对到Properties对象
store,将Properties中的键值对存储到配置文件中,如果含有中文,会存储为unicode码
@Test
public void PropertiesRead(){
Properties properties = new Properties();
String filePath="D:\\untitled1\\src\\input\\mysql.properties";
FileReader fileReader=null;
try {
fileReader =new FileReader(filePath); //获取配置文件
properties.load(fileReader); //将配置文件加载到properties这个对象中
properties.list(System.out); //将properties内的信息打印到一个位置
String user=properties.getProperty("user");
System.out.println();
System.out.println(user);
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
if (fileReader!=null){
try {
fileReader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
@Test
public void PropertiesWrite(){
Properties properties = new Properties();
String filePath="D:\\untitled1\\src\\input\\mysql1.properties";
FileWriter fileWriter =null;
try {
fileWriter = new FileWriter(filePath);
properties.setProperty("user","OLDERHARD");
properties.setProperty("password","342423");
properties.store(fileWriter,null);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (fileWriter!=null){
try {
fileWriter.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}