java基础之IO流
来源:互联网 发布:贵州6频道网络电视 编辑:程序博客网 时间:2024/05/17 06:05
所谓的IO流,即Input/Output流,主要是用来处理设备之间的数据传输的。Java对数据的传输就是通过流的方式,它对于流的操作都封装在了java.io.*包中。
对于流来说,如果谈到其操作的数据,一般就分为字符流和字节流,而谈到流向的话,那就是输入输出流。
字节流的抽象基类:InputStream,OutputStream;
字符流的抽象基类:Reader,Writer;
它们的子类均是以父类名为后缀,如FileInputStream,前缀为功能。
如何区别字节流和字符流
字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好!如果是音频文件、图片、歌曲,就用字节流好点,如果是关系到中文(文本)的,用字符流好点。
所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以形成字节序列。
字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串;字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以。
==================我们还可以看到:============
Reader类的read()方法返回类型为int :作为整数读取的字符(占两个字节共16位),范围在 0 到 65535 之间 (0x00-0xffff),如果已到达流的末尾,则返回 -1。
InputStream的read()虽然也返回int,但由于此类是面向字节流的,一个字节占8个位,所以返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。因此对于不能用0-255来表示的值就得用字符流来读取!比如说汉字。
FileWriter
由于IO流是用于操作数据的,而我们最常见的体现形式就是文件。
对于FileReader和FileWriter来说,创建对象时,必须要明确被操作的文件。其中FileWriter会将文件创建到指定的目录,如果该目录下已经有文件存在,就会对其进行覆盖;如果没有的话,就会立即创建。
public static void main(String[] args) throws IOException { FileWriter fw=null; try { //必须得指定数据要存的地方 fw=new FileWriter("D:\\1.txt"); //将字符串写入到流中 fw.write("adajll的含量"); //刷新流对象中的缓冲的数据,将数据刷到目的地中 fw.flush(); } catch (IOException e) { System.out.println(e.toString()); } finally{ try { if(fw!=null) //关闭资源,但关闭后会刷新一次内部的缓冲中的数据 //flush刷新完后流可以继续使用,但close刷新后关闭 fw.close(); } catch (IOException e2) { System.out.println(e2.toString()); } } }
可以看到,对于IO流,会经常抛异常,如IOException,FileNotFoundException….所以会建立如上代码所示的,在外建立引用,在内建立异常。
对于fw=new FileWriter(“D:\1.txt”),流是将数据刷到指定的地址,如果该地址中已存在1.txt文件,那么流会将内容进行覆盖,而如果没有存在,则直接在该地址下创建文件。也可以设置其为不覆盖。
fw=new FileWriter(“D:\1.txt”,true);传递参数true即为不覆盖原有内容,并在文件的末尾继续写入数据。
FileReader
说到了文件的写,自然也就会相对应的谈到文件的读,与FileWriter对应的为FileReader。
FileReader有两种读取方式,一种是以单个字符进行读取,一种是以字符数组进行读取。
第一种方式:单个字符进行读取
public static void main(String[] args) throws IOException { FileReader fr=null; try { //必须得指定数据从哪儿获取,若无该文件,发生FileNotFoundExeption fr=new FileReader("D:\\1.txt"); int ch=0; //结束标志为ch=-1 while((ch=fr.read())!=-1){ System.out.print((char)ch); } } catch (IOException e) { System.out.println(e.toString()); } finally{ try { if(fr!=null) //关闭资源,但关闭后会刷新一次内部的缓冲中的数据 fr.close(); } catch (IOException e2) { System.out.println(e2.toString()); } } }
对于Reader来说,读的是字符流,可以读中英文,是一个字符一个字符读的,读取的结果是字符的ASCII码值,由于read()方法是自动往下读的,因此设置了一个int ch=0来获得当前读到的字符,只要不遇到结束符-1就可以一直读取数据。读取到的码值ch要将其转化为字符输出
第二种方式:以数组进行读取
public static void main(String[] args) throws IOException { FileReader fr=null; try { //必须得指定数据存储的地方 fr=new FileReader("D:\\1.txt"); char[] chs=new char[1024]; int num=0; while((num=fr.read(chs))!=-1){ System.out.print(new String(chs,0,num)); } } catch (IOException e) { System.out.println(e.toString()); } finally{ try { if(fr!=null) fr.close(); } catch (IOException e2) { System.out.println(e2.toString()); } } }
如上代码所示,在读取之前定义了一个字符数组chs,初始化容量为1024,相当于每次读取到的是1kb的大小,比较优化。read(char[])的返回值是读取到的字符的个数。所以在循环当中输出的是new String(chs,0,num)。它的结束标志也是num!=-1,其内部实现其实就是一个字符一个字符的读。
Buffer提高读写效率
缓冲区要结合流来进行使用,在流的基础上对流的功能进行增强。它的出现,提高了对数据的读写效率。和读写相对应的,缓冲区也分为BufferedReader和BufferedWriter两类,一个针对读,一个针对写。
由于是针对流的操作,因此在使用缓冲区时,先要进行流的读写,再放入缓存区,进行操作。
BufferedReader
public static void main(String[] args) throws IOException { FileReader fr=null; BufferedReader br=null; try { //缓冲区是基于流的,因此要先使用流 fr=new FileReader("D:\\1.txt"); br=new BufferedReader(fr); String line=null; while((line=br.readLine())!=null){ System.out.println(line); } } catch (IOException e) { System.out.println(e.toString()); } finally{ try { if(br!=null) br.close(); } catch (IOException e2) { System.out.println(e2.toString()); } } }
如上代码所示,对于缓存区来说,它提供了一个一次可以读一行的方法readLine,方便于对文本数据的获取,当返回null时,表示读到了文件末尾。由于while循环判断了当前的行的内容,相当于运行了一次readLine,所以在这之前定义一个字符串,将当前行赋值给字符串,然后对字符串进行输出,否则容易出现隔行读。
在最后关闭的时候,关闭的是缓冲区,而没有关闭流对象,这是因为,关闭缓冲区,即是关闭缓冲区的流对象,所以不用再写fw.close()。
BufferedWriter
public static void main(String[] args) throws IOException { FileWriter fw=null; BufferedWriter bw=null; try { //必须得指定数据要存的地方 fw=new FileWriter("D:\\1.txt"); bw=new BufferedWriter(fw); int index=0; while(index<3){ bw.write("缓冲区写入"+index); bw.newLine();//换行 bw.flush(); index++; } } catch (IOException e) { System.out.println(e.toString()); } finally{ try { if(bw!=null) bw.close(); } catch (IOException e2) { System.out.println(e2.toString()); } } }
BufferedWriter提供了一个换行方法newLine。其余的和writer区别不大。同时,BufferedWriter和BufferedReader可以进行交互,读取到文件中的数据,再写入到另外一个文件。写的方式大致和读类似,可以一个字符一个字符的写,也可以字符数组形式进行写入新文件,还可以利用缓冲区一行一行的读,再写入。如下,利用缓冲区来进行读写交互。
public static void main(String[] args) throws IOException { FileReader fr=null; FileWriter fw=null; BufferedWriter bw=null; BufferedReader br=null; try { fr=new FileReader("D:\\1.txt"); br=new BufferedReader(fr); //必须得指定数据要存的地方 fw=new FileWriter("D:\\2.txt"); bw=new BufferedWriter(fw); String line=null; while((line=br.readLine())!=null){ bw.write(line); bw.newLine(); bw.flush(); } } catch (IOException e) { System.out.println(e.toString()); } finally{ try { if(bw!=null && br!=null) { //关闭两流资源,关闭缓冲区即可 bw.close(); br.close(); } } catch (IOException e2) { System.out.println(e2.toString()); } } }
****readLine方法原理:无论是读一行还是读取多个字符,最终底层实现都是在硬盘上一个一个读取。所以底层还是使用的是read方法,一次读取一个。
字节流InputStream OutputStream
如上的字符流,只用来处理文本信息。对于字节流,就使用的是InputStream和OutputStream,与之相对应的就是Flie,Buffer,加起来也是四个。
public static void main(String[] args) throws IOException { FileOutputStream out=new FileOutputStream("D:\\1.txt"); out.write("测试字节流输出".getBytes()); FileInputStream in=new FileInputStream("D:\\1.txt"); int ch=0; while((ch=in.read())!=-1) { System.out.print((char)ch); } }
如上代码所示,字节输出流在写入的时候,要将字符串变成byte数组,其他和字符流的没啥差别,也可以单个字节写入,也可以字符数组写入,但是buffer对应的没有了换行的newLine方法。
字节输入流和reader的区别也不大,也是单字符读和多字符读,buffer对应的方式少了读取一行的方法。
InputStreamReader OutputStreamWriter
InputStreamReader,字节输入流向字符输入流转化的桥梁。
将inputStream转化以后,就可以使用bufferedReader的方法了。
同理,outputStreamWriter是字节输出流转字符输出流的桥梁,转换完成就可以使用bufferedwriter的方法,如newLine等。
BufferedReader br =new BufferedReader(new InputStreamReader(System.in));BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(System.out));
存储时需要制定编码表时,可以使用转换流。因为只有转换流才可以指定、FileWriter默认使用编码表GBK。
public static void main(String[] args) throws IOException { OutputStreamWriter out =new OutputStreamWriter(System.out, "utf-8"); BufferedWriter bw=new BufferedWriter(out); InputStreamReader in =new InputStreamReader(System.in, "utf-8"); BufferedReader br=new BufferedReader(in); }
文件File类
流在操作数据的时候,最大的体现就是文件。
File类就是将文件或文件夹封装为对象,方便对其属性信息进行操作。
文件的创建
File file=new File(“a.txt”);
File file=new File(“C:\”,”b.txt”);
file.createFile();
文件的创建如上所示,如未指定路径,则在当前项目下创建文件,如果指定则在指定目录下创建。
若文件不存在,则创建;若已存在,则不创建,并返回false,和输出流不一样,文件不会对已存在对象进行覆盖。
删除文件
boolean delete();删除失败返回false,
void deleteOnExit(),程序结束时才删除文件
判断文件是否存在
boolean exists();文件是否存在。
创建文件夹 File f=new File(“abc”);
boolean mkdir();创建文件夹。 file.mkdir();
Boolean mkdirs(),创建多级文件夹。
判断是否是目录
boolean isDirectory,在判断之前先判断文件是否存在, isFile();
获取信息
getPath, getAbsolutePath, getName,getLength….
getParent返回绝对路径中的父目录,否则返回null.如果是相对路径,有上一层目录的话,返回上一层目录。
File[] files=File.listRoots();打印盘符
String[] names=file.list();//打印某路径下的所有文件及文件夹
过滤文件,代码如下:
public static void main(String[] args) throws IOException { File dirFile=new File("D:\\WorkSpace\\test\\src\\test"); String[] names=dirFile.list(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.startsWith("Test"); } }); for(String name:names){ System.out.println(name); } }
此处使用了过滤文件名的匿名内部类,结果如下:
File[] files=dir.listFiles();//列出某目录下的所有文件。
为了代码的可移植性,一般采用File.separator来代替手写的磁盘分隔符。
Properties
Properties是hashtable的子类,具备map集合的特点,里面存储的是字符串类型的键值对。一般用来匹配文件。
Properties pro=new Properties();
pro.setPorperty(“xxx”,”xxxx”);
pro.getProperty(“xxx”);//类似于map的put 和get。
用其存取配置文件,通过流读取到该配置文件,然后用”=”切割。其中左边为键,右边为值。
对于非缓冲区流来说,必须得在pro里面加载流。pro.load(fileinputStream);加载数据时,需要固定格式:键=值。
打印流PrintStream PrintWriter
打印流,即提供了打印方法,可以将各种数据类型都原样打印。
字节打印流PrintStream,构造函数可接收的类型,如:file对象,String字符串,outputStream字节输出流。
字符打印流,PrintWriter,在字节的几种类型上多一个,Writer字符输出流。
操作对象
ObjectInputStream,ObjectOutputStream,被操作的对象必须实现Serializable标记接口。无方法的接口,即给类一个资格以序列化。其中包含uid,如果类改变,则uid也会发生变化。即对象的序列化。
write:
public static void main(String[] args) throws IOException { ObjectOutputStream oos=new ObjectOutputStream( new FileOutputStream("obj.txt")); oos.writeObject(new Person("liming",30)); oos.close(); }
将对象序列化以后存入内存当中,对我们来说可能看不懂,但主机会识别。其中,Person类必须实现Serializable接口。
read
public static void main(String[] args) throws IOException { ObjectInputStream ois=new ObjectInputStream( new FileInputStream("obj.txt")); Person p=(Person)ois.readObject(); ois.close(); }
类一改变,UID即改变,obj.txt不对应,就不允许读写。序列号是根据成员来的,改变私有化等也会改变UID。可以自定义UID来解决上述问题。
public static final long serialVersionUID=42L;
注意:静态是不能被序列化的,因为在方法区,而对象在堆中。非静态的,若以transient修饰,也不会被序列化,但仍会在堆内存中存在。
管道流
管道流,PipedInputStream,PipedOutputStream。输入和输出可以直接相连,通过应用在多线程中,单线程会出现死锁。
public static void main(String[] args) throws IOException { PipedInputStream in=new PipedInputStream(); PipedOutputStream out=new PipedOutputStream(); in.connect(out); //多线程中传入in和out,然后启动线程 }
字符编码
ASCII; ISO8859-1; GB2312; GBK;Unicode,UTF-8
GBK:4字节,UTF-8:6字节
String –>byte[] : str.getBytes();
打印byte: Arrays.toString(b1);
byte[]–>String: new String(byte[],charsetName);(“GBK”,“UTF-8”)
解码错误的时候,先按错误的再编码一次,再按原编码对其解码。
- java基础之 IO流
- Java基础之IO流
- Java基础之IO流
- Java基础之IO流
- Java基础之IO流
- JAVA基础之IO流
- java基础之IO流
- java基础之io流
- java基础之io流
- Java基础之IO流
- java基础之IO流
- Java基础之IO流
- Java基础之IO流
- java基础之io
- java基础之IO
- java基础之IO
- java基础之IO
- Java基础之IO
- Maven构建跳过单元测试
- 《捕鱼游戏》隐私政策
- Leetcode 1. Two Sum
- linux的ls命令详解(二)
- 计算机网络体系结构——物理层
- java基础之IO流
- 解决 Python 出现的UnicodeDecodeError: 'ascii' codec can't decode byte 0xe9
- opencv标准霍夫变换检测直线以及描绘每条线段中pt1、pt2点的确定
- Efficient Inference in Fully Connected CRFs with Gaussian Edge Potentials之python代码运行
- ubuntu16.04 u 盘安装
- js typeof表达式
- 基于Spring MVC框架搭建项目
- 小知识
- memcache简单介绍