Jave中IO的详细总结
前语
如果你仅仅就是想读取以及存文本文件和图片之类的文件,可以直接看字节流的两个案例或者效率更高的缓冲字节流。
如果仅仅想要对文本文件进行读写,可以看最常用的复制文件的方式。
IO流概述和分类
IO流介绍
IO:输入/输出(Input/Output)
流:是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输
IO流就是用来处理设备间数据传输问题的。
常见的应用:文件复制;文件上传;文件下载
IO流的分类
- 按照数据的流向:
- 输入流:读数据
- 输出流:写数据
- 按照数据类型来分
- 字节流
- 字节输入流
- 字节输出流
- 字符流
- 字符输入流
- 字符输出流
- 字节流
IO流的使用场景
- 如果操作的是纯文本文件,优先使用字符流
- 如果操作的是图片、视频、音频等二进制文件。优先使用字节流
- 如果不确定文件类型,优先使用字节流。字节流是万能的流
File文件是干嘛的
File文件就是在程序中设置的一个可以表示具体文件的一个对象,你仅仅File file = new File(—)是不会产生真实对象的,就是一种表示方式。
package file_test;
import java.io.File;
//import java.io.FileReader;
import java.io.IOException;
public class FileDemo02 {
public static void main(String[] args) throws IOException {
File f1 = new File("C:\\Users\\45512\\Desktop\\java试验文件\\java.txt");
System.out.println(f1.createNewFile());
System.out.println("-------------");
File f2 = new File("C:\\Users\\45512\\Desktop\\java试验文件\\JavaSE");
System.out.println(f2.mkdir());
System.out.println("----------");
File f3 = new File("C:\\Users\\45512\\Desktop\\java试验文件\\JavaWEB\\HTNL");
System.out.println(f3.mkdirs());
System.out.println("-------");
File f4 = new File("C:\\Users\\45512\\Desktop\\java试验文件\\javase.txt");
System.out.println(f4.createNewFile());
}
}
字节流
网上关于文字的述说有许多,个人感觉只有概念没有实例是无法领会知识的真正含义的,在这里我将以代码的形式向大家展现:
字节流的写入
package file_test;
/*
字节流写入数据分3步:
1.创建字节输出流对象
2.调用write方法写入数据
3.释放资源
*/
//import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo01 {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("C:\\Users\\45512\\CAJ_wenjian\\fos.txt");
/*
做了3件事:
1.调用系统创建了文件
2.创建了字节输出流对象
3.让字节输出流对象指向创建好的文件
*/
fos.write(97);//被转化成了a
fos.write(57);
fos.write(55);//这两个可以凑97
fos.close();
/*
做了2件事:
1.关闭此文件输出流
2.释放此流相关联得任何系统资源
*/
}
}
txt文件:
字节流三种不同的写入方式:
package file_test;
import java.io.File;
//import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutStreamDemo02 {
public static void main(String[] args) throws IOException {
File file = new File("C:\\Users\\45512\\CAJ_wenjian\\fos.txt");
FileOutputStream fos = new FileOutputStream(file);
//下面的和上面的相同
//FileOutputStream fos = new FileOutputStream("C:\\Users\\45512\\CAJ_wenjian\\fos.txt");
//FileOutputStream fos = new FileOutputStream("new File(C:\\Users\\45512\\CAJ_wenjian\\fos.txt)");
fos.write(97);
fos.write(98);
fos.write(99);
fos.write(100);
fos.write(101);
byte[] bys = {97,98,99,100,101};
fos.write(bys);
//getBytes():返回字符串对应的字节数组
//\r\n在windows操作系统中是换行的意思
fos.write("\r\nabcde".getBytes());
fos.write(bys,0,bys.length);//从第0位起后length长度
fos.write(bys,1,3);
//如何写追加写入的文件————在创建文件的时候解决,后面加一个
FileOutputStream fos2 = new FileOutputStream("C:\\Users\\45512\\CAJ_wenjian\\fos1.txt",true);
for (int i=0;i<5;i++){
fos2.write("helloWorld".getBytes());
fos2.write("\r\n".getBytes());
}
fos.close();
}
}
运行一次后txt的文件:
运行两次后txt的文件:
上面都是用throws抛出异常,那么,如果不要抛出异常,要解决异常又该怎么写呢?
package file_test;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo03 {
public static void main(String[] args) {
FileOutputStream fos = null;
//这里如果=null不写则会报错,因为fos没有进行初始化
try {
fos = new FileOutputStream("C:\\Users\\45512\\CAJ_wenjian\\fos.txt");
fos.write("hello".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
为什么要将close写到finally里面呢?大家不妨思考一下。
如果将其放在try里面,当文件路径不存在时,系统资源就无法释放。那为什么要在finally里面套上if语句哩?这是为了增强程序的健壮性,如果文件不存在,则fos是null,null.close(),就会报空指针异常。
字节流的读入
先给上需要读入的txt文件:
再给上代码,一切便清晰了。
package file_test;
import java.io.FileInputStream;
//import java.io.FileNotFoundException;
import java.io.IOException;
/*
字节流写入数据分3步:
1.创建字节输入流对象
2.调用read()方法//如果文件到达末尾,返回值就是-1
3.释放资源
*/
public class FileInputStreamDemo01 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("C:\\Users\\45512\\CAJ_wenjian\\fos.txt");
FileInputStream fis2 = new FileInputStream("C:\\Users\\45512\\CAJ_wenjian\\fos.txt");
/*
//第一次读取数据
int by = fis.read();
System.out.println(by);//97
System.out.println((char)by);//a
//第二次读取数据
by = fis.read();
System.out.println(by);//98
System.out.println((char)by);//b
*/
int by = fis.read();
while (by!=-1){
System.out.print((char)by);
by = fis.read();//如果不进行读取,则始终读取第一位数
}
System.out.println("\n--------");
//优化上面的代码,标准读入代码
int by1;
while ((by1=fis2.read())!=-1){
System.out.print((char)by1);
}
fis.close();
fis2.close();
}
}
下面是字节流读数据到控制台操作,首先给上txt文件:
package file_test;
import java.io.*;
public class FileInputStreamDemo02{
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("C:\\Users\\45512\\CAJ_wenjian\\fos.txt");
byte[] bys = new byte[5];
//第一次读取数据
int len = fis.read(bys);//len指读取的字节的长度
System.out.println(len);
System.out.println(new String(bys,0,len));
//第二次读取数据
len = fis.read(bys);
System.out.println(len);
System.out.println(new String(bys,0,len));
//第三次读取数据
len = fis.read(bys);
System.out.println(len);
System.out.println(new String(bys,0,len));
/*
注意记事本world后要按一个Enter键
hello\r\n
world\r\n
下面是System.out.println(new String(bys));的结果
第一次读取数据时:h e l l o
第一次读取数据时:\r \n w o r
第三次读取数据时:l d \r \n r(r没有替换保留)
*/
fis.close();
}
}
下面是将 System.out.print(new String(bys))改成System.out.println(new String(bys,0,len));的结果
当然最实用的是下面的循环代码:
package file_test;
import java.io.*;
public class FileInputStreamDemo02{
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("C:\\Users\\45512\\CAJ_wenjian\\fos.txt");
byte[] bys = new byte[1024];//1024的整数倍
int len;
while((len=fis.read(bys))!=-1){
System.out.print(new String(bys,0,len));
}
fis.close();
}
}
字节流案例:复制文本文件
把一个txt文件里面的内容复制到另一个txt文件中。
原文件:
package file_test;
import java.io.FileInputStream;
//import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyTxtDemo {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("C:\\Users\\45512\\CAJ_wenjian\\fos.txt");
FileOutputStream fos = new FileOutputStream("C:\\Users\\45512\\CAJ_wenjian\\fos1.txt");
int x;
while ((x=fis.read())!=-1){
fos.write(x);
}
fis.close();
fos.close();
}
复制后得到的fos1.txt文件
字节流案例:复制图片文件
package file_test;
import java.io.FileInputStream;
//import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyTxtDemo {
public static void main(String[] args) throws IOException {
/*FileInputStream fis = new FileInputStream("C:\\Users\\45512\\CAJ_wenjian\\fos.txt");
FileOutputStream fos = new FileOutputStream("C:\\Users\\45512\\CAJ_wenjian\\fos1.txt");
int x;
while ((x=fis.read())!=-1){
fos.write(x);
System.out.println(x);
}
fis.close();
fos.close();*/
FileInputStream fis = new FileInputStream("C:\\Users\\45512\\Desktop\\java学习资料\\素材\\itcast\\mn.jpg");
FileOutputStream fos = new FileOutputStream("C:\\Users\\45512\\CAJ_wenjian\\mn.jpg");
byte[] bys = new byte[1024];
int len;
while((len=fis.read(bys))!=-1){
fos.write(bys);
}
fos.close();
fis.close();
}
}
字节缓冲流介绍
- BufferOutputStream:该类实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
- BufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
- 简而言之,字节缓冲流可以提高效率,需要注意的是,字节缓冲流仅仅提供缓冲区,而真正的读写还得依靠基本的字节流对象进行操作。
package file_test;
import java.io.*;
//import java.io.FileNotFoundException;
public class BufferStreamDemo {
public static void main(String[] args) throws IOException {
/*FileOutputStream fos = new FileOutputStream("C:\\Users\\45512\\CAJ_wenjian\\bos.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);*/
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\45512\\CAJ_wenjian\\bos.txt"));
bos.write("hello\r\n".getBytes());
bos.write("world\r\n".getBytes());
bos.close();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\45512\\CAJ_wenjian\\bos.txt"));
/*
读数据的第一种方式
int by;
while ((by=bis.read())!=-1){
System.out.print((char)by);
}*/
//读数据的第二种方式
byte[] bys = new byte[1024];
int len;
while((len=bis.read(bys))!=-1){
System.out.print(new String(bys,0,len));
}
bis.close();
}
}
字符流
为什么会出现字符流
- 字符流的介绍
由于字节流操作中文不是特别的方便,所以Java就提供字符流
字符流 = 字节流 + 编码表 - 中文的字节存储方式
用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,如何识别是中文的呢?汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数(UTF-8一个汉字对应3个字节,GBK一个汉字对应2个字节)
字符串和字符流中的编码解码问题
package file_test;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class StringDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "中国";
//编码
//byte[] getBytes():使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中
byte[] bys = s.getBytes();//默认用UTF-8编码,结果:[-28, -72, -83, -27, -101, -67]
//byte[] bys = s.getBytes("GBK");//指定编码为GBK(需要抛出异常),结果:[-42, -48, -71, -6]
System.out.println(Arrays.toString(bys));
//解码
String ss = new String(bys);//使用平台的默认字符集解码,结果:中国
//String ss = new String(bys,"GBK");//使用指定的默认字符集解码,结果:涓浗
System.out.println(ss);
}
}
package file_test;
import java.io.*;
public class ConversionStreamDemo {
public static void main(String[] args) throws IOException {
// FileOutputStream fos = new FileOutputStream("C:\\Users\\45512\\CAJ_wenjian\\osw.txt");
// OutputStreamWriter osw = new OutputStreamWriter(fos);
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("C:\\Users\\45512\\CAJ_wenjian\\osw.txt"));
//下面这个就是以指定的编码方式进行编码
// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("C:\\Users\\45512\\CAJ_wenjian\\osw.txt"),"UTF-8");
osw.write("中国");
osw.close();
InputStreamReader isr = new InputStreamReader(new FileInputStream("C:\\Users\\45512\\CAJ_wenjian\\osw.txt"));
//一次读取一个字符数据
int ch;
while ((ch=isr.read())!=-1){
System.out.print((char)ch);
}
isr.close();
}
}
字符流写文件的5种方式
其中第4种用得最多。
package file_test;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class OutputStreamWriteDemo {
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("C:\\Users\\45512\\CAJ_wenjian\\osw.txt"));
//void write(int c)
osw.write(97);
osw.flush();//刷新流,不刷新文本不显示
osw.write(98);
osw.write("\r\n");
//void write(char[] cbuf)
char[] chs = {'a','b','c','d','e'};
osw.write(chs);
osw.write("\r\n");
//void write(char[] cbuf,int off,int len)
char[] chs1 = {'a','b','c','d','e'};
osw.write(chs1,0,chs.length);
osw.write("\r\n");
//void write(String str);
osw.write("abdbhjd");
osw.write("\r\n");
//void write(String str,int off,int len);
osw.write("abhdjc",1,3);
osw.close();//调用close会自动刷新
}
}
字符流读数据的两种方式
package file_test;
import java.io.*;
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("C:\\Users\\45512\\CAJ_wenjian\\osw.txt"));
InputStreamReader isr1 = new InputStreamReader(new FileInputStream("C:\\Users\\45512\\CAJ_wenjian\\osw.txt"));
//int read():一次读取一个数据
int ch;
while ((ch=isr.read())!=-1){
System.out.print((char)ch);
}
System.out.println();
//int read(char[] cbuf):读字符串数组
char[] chs = new char[1024];
int len;
while((len=isr1.read(chs))!=-1){
System.out.println(new String(chs,0,len));
}
isr.close();
}
}
字符流的便捷类——FileReader和FileWriter
FileReader是OutputStreamReader的子类,用法和它差不多,但是不可以做流的编码,同理,FileWriter是OutputStreamWriter的子类。
这里就通过一个案例来进行了解吧——复制java文件。
package file_test;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyJavaDemo02 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("C:\\Users\\45512\\CAJ_wenjian\\Demo\\src\\file_test\\ConversionStreamDemo.java");
FileWriter fw = new FileWriter("C:\\Users\\45512\\CAJ_wenjian\\Demo\\src\\file_test\\Copy.java");
/* int ch;
while ((ch=fr.read())!=-1){
fw.write(ch);
}*/
char[] chs = new char[1024];
int len;
while((len=fr.read(chs))!=-1){
fw.write(chs,0,len);
}
fw.close();
fr.close();
}
}
缓冲字符流
这个是为了提高读写效率的。
和字节缓冲流也十分相似。
package file_test;
import java.io.*;
public class BufferedStreamDEmo01 {
public static void main(String[] args) throws IOException{
BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\45512\\CAJ_wenjian\\bw.txt"));
bw.write("hello\r\n");
bw.write("world\r\n");
bw.close();
BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\45512\\CAJ_wenjian\\bw.txt"));
int ch;
while((ch=br.read())!=-1){
System.out.print((char)ch);
}
/*
char[] chs = new char[1024];
int len;
while((len=br.read(chs))!=-1){
System.out.println(new String(chs,0,len));
}*/
br.close();
}
}
字节缓冲流有什么特有更能呢?下面我们来看一下:
- BufferdWriter():
void newLine():写一行行分隔符,行分隔符字符串由系统属性定义。 - Buffer额度Reader:
public String readline():读一行文字。结果包含行的内容的字符串,不包括任何终止字符(即不包括换行符),如果流的结尾已经到达,则为null。
package file_test;
import java.io.*;
public class BufferedStreamDemo02 {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\45512\\CAJ_wenjian\\bw.txt"));
for (int i = 0; i < 10; i++) {
bw.write("hello" + i);
//bw.write("\r\n");这个方法只适合windows系统,不太好
bw.newLine();
bw.flush();
//该方法写入数据这三条语句都要写
}
bw.close();
BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\45512\\CAJ_wenjian\\bw.txt"));
String line;
while ((line=br.readLine())!=null){
System.out.println(line);
}
br.close();
}
}
最常用的复制文件的方式
package file_test;
import java.io.*;
public class CopyJavaDemo03 {
public static void main(String[] args) throws IOException {
BufferedReader br= new BufferedReader(new FileReader("C:\\Users\\45512\\CAJ_wenjian\\Demo\\src\\file_test\\ConversionStreamDemo.java"));
BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\45512\\CAJ_wenjian\\Demo\\src\\file_test\\Copy.java"));
String line;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();;
br.close();
}
IO小结
至此,IO的大部分知识结束了,你掌握了吗?
如果对你有帮助的话,不妨点个赞呗!