Java基础--常用API--IO流相关API
一、io流
1、定义:
io流指的是input/output流,即输入流/输出流。
输入流:将外界信息写入程序,即从外界获取信息,属于读操作。
输出流:将程序数据发送给外界,即向外界传输数据,属于写操作。
流一定要关闭,否则可能会出现一些异常。
2、分类:
(1)按照功能划分:
输入流:只能读数据,不能写数据。
输出流:只能写数据,不能读数据。
(2)按照处理单元划分:
字节流:读写字节,基类为inputstream/outputstream。
字符流:读写字符,基类为reader/writer。(底层基于字节流进行操作,自动搜寻指定的编码集合并转换)
(3)按照角色划分:
节点流(低级流):直接从外部设备中读写数据。
处理流(高级流):处理一个已存在的流,不单独存在。
3、常用类与接口:
java中i/o处理的相关类库主要存放在 java.io 包中。
基于字节操作的 i/o 类:inputstream 和 outputstream
基于字符操作的 i/o 类:reader 和 writer
基于磁盘操作的 i/o 类:file
关闭i/o流的接口:closeable
刷新i/o流的接口:flushable
序列化接口:serializable
二、字节流
1、字节输入流:
字节输入流的基类是inputstream,常用的子类是fileinputstream、bufferedinputstream。
(1)、inputstream
所有字节输入流的父类。
常用方法: int read()// 读取并返回1字节数据,若返回-1,表示读到了输入流的末尾。 int read(byte[] b)// 将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。 int read(byte[] b, int off, int len)//将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾,off指定在数组b中存放数据的起始偏移位置;len指定读取的最大字节数。 long skip(long n)// 跳过和丢弃此输入流中数据的n个字节 void close()// 关闭此输入流并释放与该流关联的所有系统资源。
(2)、fileinputstream
文件字节输入流,低级流。所有文件在系统中均以字节的形式保存,可以使用fileinputstream去读取保存在硬盘上的字节序列。
在创建时,将文件名作为构造参数来创建fileinputstream,从而与文件间建立起字节流传输通道。
通过read()、read(byte[])、read(byte[], int begin, int len)三种方法从字节流中读取一个字节或一组字节。
常用方法: 继承并重写父类(inputstream)的方法。 构造方法: fileinputstream(file file)// 通过打开一个到实际文件的连接来创建一个fileinputstream,该文件通过文件系统中的file对象file指定 fileinputstream(string name) // 通过打开一个到实际文件的连接来创建一个fileinputstream,该文件通过文件系统中的路径name指定 样例: import java.io.file; import java.io.fileinputstream; import java.io.filenotfoundexception; import java.io.ioexception; public class fisdemo{ public static void main(string[] args) { fileinputstream fis = null; try { // 注:此处的test.txt由自己新建,没有的话会报异常的,此处我在文件内部写了 “hello world”。 fis = new fileinputstream("src" + file.separator + "test.txt");// 与文件建立个字节传输通道 byte[] b = new byte[1024];// 用于保存从文件读取的字节 try { system.out.println("开始读取文件"); int len = 1; while ((len = fis.read(b)) != -1) {// 循环读取文件 string str = new string(b, "utf-8");// 将字节数组转为字符串 system.out.println(str);// 输出 } if (len == -1) { system.out.println("文件读取完毕"); } } catch (ioexception e) { e.printstacktrace(); system.out.println("读取文件异常"); } } catch (filenotfoundexception e) { e.printstacktrace(); system.out.println("文件异常"); } finally { try { fis.close();// 关流 } catch (ioexception e) { e.printstacktrace(); system.out.println("系统异常"); } } } } 结果: 开始读取文件 hello world 你好 文件读取完毕
(3)、bufferedinputstream
带缓冲的字节输入流,高级流。若直接从文件中存取字节流,则可能受硬件的影响导致传输速度慢,解决办法:先在内存中建立一个缓冲区,每次将字节流从硬件中读取到缓冲区中,然后从内存中读取字节流。由于计算机与内存的交互速度比磁盘的交互速度快,所以效率会提高。
常用方法: 继承并重写父类(inputstream)的方法。 构造方法: bufferedinputstream(inputstream in)// 创建一个bufferedinputstream并保存其参数,即输入流in,以便将来使用。 bufferedinputstream(inputstream in, int size) // 创建具有指定缓冲区大小的bufferedinputstream并保存其参数,即输入流in以便将来使用 样例: fileinputstream fis = new fileinputstream("src" + file.separator + "test.txt");// 与文件建立个字节传输通道 bufferedinputstream bis = new bufferedinputstream(fis);//用于操作字节流 其余操作与fileinputstream类似
2、字节输出流
字节输入流的基类是outputstream,常用的子类是fileoutputstream、bufferedoutputstream。
(1)、outputstream
所有字节输出流的父类。
常用方法: void write(byte[] b)// 将b.length个字节从指定的byte数组写入此输出流 void write(byte[] b, int off, int len)// 将指定byte数组中从偏移量off开始的len个字节写入此输出流 void write(int b)// 将1字节写入此输出流 void close() // 关闭此输出流并释放与此流有关的所有系统资源 void flush() // 刷新此输出流并强制写出所有缓冲的输出字节
(2)、fileoutputstream
文件字节输出流,低级流。所有文件在系统中均以字节的形式保存,可以使用fileoutputstream将字节流输出并保存在硬件中。
在创建时,将文件名作为构造参数来创建fileoutputstream,从而与文件间建立起字节流传输通道。
常用方法: 继承并重写父类(outputstream)的方法。 构造方法: fileoutputstream(file file);//其中file指文件名 fileoutputstream(string pathname);//其中pathname指文件路径 fileoutputstream(string pathname, boolean append);//其中append为true时,则表示向文件末尾追加数据,默认为false,即覆盖数据。 样例: import java.io.file; import java.io.filenotfoundexception; import java.io.fileoutputstream; import java.io.ioexception; public class fosdemo { public static void main(string[] args) { fileoutputstream fos = null; try { fos = new fileoutputstream("src" + file.separator + "test.txt");// 与文件间建立个通道,此时会覆盖原文件 string str = "how are you"; byte[] b = str.getbytes(); try { system.out.println("开始文件写操作"); fos.write(b); system.out.println("文件写操作完成"); } catch (ioexception e) { e.printstacktrace(); system.out.println("文件写入异常"); } } catch (filenotfoundexception e) { e.printstacktrace(); system.out.println("文件异常"); }finally { try { fos.close(); } catch (ioexception e) { e.printstacktrace(); system.out.println("系统异常"); } } } } 结果: 开始文件写操作 文件写操作完成 再次执行fisdemo.java后,结果为: 开始读取文件 how are you 文件读取完毕 即覆盖了原文件。
(3)、bufferedoutputstream
缓冲字节输出流,高级流。将字节流输出到缓冲区,通过flush方法可以将其写入到硬件中。
常用方法: 继承并重写父类(outputstream)的方法。 构造方法: bufferedoutputstream(outputstream out)// 创建一个新的缓冲输出流,以将数据写入指定的底层输出流 bufferedoutputstream(outputstream out, int size)// 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流 样例: fileoutputstream fos = new fileoutputstream("src" + file.separator + "test.txt");// 与文件建立个字节传输通道 bufferedoutputstreambis = new bufferedoutputstream(fos);//用于操作字节流 其余操作与fileoutputstream类似
三、字符流
注意:字符流只用于读写文本数据,不能用于读取图片等数据。
1、字符输入流
字符输入流的基类是reader。常用类为inputstreamreader,bufferedreader。
(1)reader
常用方法: int read()// 读取并返回1字符数据,若返回-1,表示读到了输入流的末尾。 int read(char[] b)// 将数据读入一个字符数组,同时返回实际读取的字符数。如果返回-1,表示读到了输入流的末尾。 int read(char[] b, int off, int len)//将数据读入一个字符数组,同时返回实际读取的字符数。如果返回-1,表示读到了输入流的末尾,off指定在数组b中存放数据的起始偏移位置;len指定读取的最大字符数。 long skip(long n)// 跳过和丢弃此输入流中数据的n个字符 void close()// 关闭此输入流并释放与该流关联的所有系统资源。
(2)inputstreamreader
inputstreamreader是字符输入流,可以在构造方法中设置字符集,并按照该编码将字节数据转为字符并读取。
构造方法为: inputstreamreader(inputstream in); inputstreamreader(inputstream in, string charsetname);其中charsetname指utf-8、gbk等编码集。
(3)bufferedreader
bufferedreader是缓冲字符输入流,以行为单位读取字符串,其对应的应该为bufferedwriter,但其没有printwriter用的爽。
构造方法: bufferedreader(reader paramreader); 常用方法: string readline();一次读取一行字符串,若返回null,则表示无数据可读。 字符流一般使用流程: fileinputstream fis = new fileinputstream("pw.txt"); //获取文件输入流 inputstreamwriter isw = new inputstreamwriter(fis, "utf-8"); //按照指定编码集包装一下io流 bufferedreader br = new bufferedreader(isw);//使用缓冲字符流包装一下io流 string str = null; while((str = br.readline() ) != null){ system.out.println(str); } fis.close(); isw.close(); br.close();
2、字符输出流
字符输出流的基类是writer。常用类为outputstreamwriter,printwriter。
(1)writer
常用方法: void write(char[] b)// 将b.length个字符从指定的byte数组写入此输出流 void write(char[] b, int off, int len)// 将指定byte数组中从偏移量off开始的len个字符写入此输出流 void write(int b)// 将1字符写入此输出流。 void write(string b)// 将字符串写入此输出流 void close() // 关闭此输出流并释放与此流有关的所有系统资源 void flush() // 刷新此输出流并强制写出所有缓冲的输出字符
(2)outputstreamwriter
outputstreamwriter是字符输出流,同样可以在构造方法中设置字符集,按照字符集将字符转为字节数据。
构造方法为: outputstreamwriter(outputstream out); outputstreamwriter(outputstream out, string charsetname);其中charsetname指utf-8、gbk等编码集。
注:向文件写入文本数据(字符串)的步骤 使用字符流时: 1、向文件中写数据,fileoutputstream fos = new fileoutputstream("aa.txt"); 2、写文本数据,outputstreamwriter osw = new outputstreamwriter(fos); 或者outputstreamwriter osw = new outputstreamwriter(fos,”utf-8“);(建议使用) 3、写字符串。 不使用字符流时,写字符串一般采用: fos.write("string".getbytes());将字符串转为字节数组,再写入文件。 使用字符流后,可以采用: osw.write("string");因为字符流支持写入字符串。
(3)printwriter
printwriter是缓冲字符输入流,具有自动行刷新功能,即以行为单位写出字符串。
构造方法: printwriter(file file); printwriter(string pathname); printwriter(outputstreamwriter osw); printwriter(writer writer); printwriter(outputstreamwriter osw, boolean autoflush); printwriter(writer writer, boolean autoflush); 要想使用行刷新,必须有流作为参数。同时可以增加第二个参数,该参数为boolean值,该值为true时,则具有了自动行刷新功能。 普通方法: void println(string str); autoflush为true时,自动调用flush(),每写一行,换行,但会增加写次数,降低效率。 使用流程: 使用默认编码集: printwriter pw = new printwriter("pw.txt"); pw.println("你好"); pw.close(); 使用自定义编码集:(建议) fileoutputstream fos = new fileoutputstream("pw.txt"); outputstreamwriter osw = new outputstreamwriter(fos, “utf-8”); printwriter pw = new printwriter(osw, true); pw.println("你好"); pw.close(); 举例: 使用缓冲字符流读每一行字符串,然后将字符串拼接,最后在向文件追加写操作,写入文件。 import java.io.bufferedreader; import java.io.fileinputstream; import java.io.fileoutputstream; import java.io.ioexception; import java.io.inputstreamreader; import java.io.outputstreamwriter; import java.io.printwriter; public class test { public static void main(string[] args) throws ioexception { // 使用字节流读取文件 fileinputstream fis = new fileinputstream("a.txt"); // 使用字符流,并指定字符集 inputstreamreader isr = new inputstreamreader(fis, "utf-8"); // 使用缓冲字符流 bufferedreader br = new bufferedreader(isr); // 使用stringbuilder,便于字符串的拼接 stringbuilder sb = new stringbuilder(); string str = null; // 循环读取每行字符串,并拼接 while ((str = br.readline()) != null) { sb.append(str); } // 将stringbuilder的值转为字符串 str = sb.tostring(); // 使用字节流写入文件 fileoutputstream fos = new fileoutputstream("a.txt", true); // 使用字符流,并指定字符集。 outputstreamwriter osw = new outputstreamwriter(fos, "utf-8"); // 使用缓冲输出流 printwriter pw = new printwriter(osw, true); // 写入文件 pw.println(str); // 关流 fis.close(); isr.close(); fos.close(); osw.close(); br.close(); pw.close(); } }
四、字节流补充
1、序列化流(objectoutputstream,objectinputstream)
序列化:将一个特定数据结构转为一组字节的过程。
反序列化:将一组字节转为特定的数据结构。
持久化:将数据写入硬盘长久保存。
序列化、反序列化一般用于传输以及保存数据。
objectoutputstream用于序列化,objectinputstream用于反序列化。是一组高级流。实现序列化需要实现serializable接口。使用transient关键字修饰的成员变量不参与序列化过程。
常用方法: void writeobject(object o);序列化,将对象转为字节写入文件。 object readobject();反序列化,将文件中字节转为对象。 样例: import java.io.file; import java.io.fileinputstream; import java.io.filenotfoundexception; import java.io.fileoutputstream; import java.io.ioexception; import java.io.objectinputstream; import java.io.objectoutputstream; import java.io.serializable; import java.util.arraylist; import java.util.list; /** * 需被序列化的类,要实现serializable接口 * * @author ebt * */ class person implements serializable { private static final long serialversionuid = 1l; private integer age; private list<string> name; public person(integer age, list<string> name) { this.age = age; this.name = name; } public integer getage() { return age; } public void setage(integer age) { this.age = age; } public list<string> getname() { return name; } public void setname(list<string> name) { this.name = name; } public string tostring() { return "person [age=" + age + ", name=" + name + "]"; } } /** * 测试类,测试序列化 * * @author ebt * */ public class serializabledemo { public static void main(string[] args) { list<string> name = new arraylist<string>(); name.add("张三"); name.add("李四"); person person = new person(18, name); fileoutputstream fos = null; objectoutputstream oos = null; try { fos = new fileoutputstream("src" + file.separator + "test.txt"); try { oos = new objectoutputstream(fos); system.out.println("开始序列化"); oos.writeobject(person); system.out.println("序列化完成"); } catch (ioexception e) { e.printstacktrace(); system.out.println("序列化异常"); } } catch (filenotfoundexception e) { e.printstacktrace(); system.out.println("文件异常"); } finally { try { fos.close(); oos.close(); } catch (ioexception e) { e.printstacktrace(); system.out.println("系统异常"); } } fileinputstream fis = null; objectinputstream ois = null; try { fis = new fileinputstream("src" + file.separator + "test.txt"); try { ois = new objectinputstream(fis); try { system.out.println("\n\n开始反序列化"); person people = (person) ois.readobject(); system.out.println(people); system.out.println("反序列化结束"); } catch (classnotfoundexception e) { e.printstacktrace(); system.out.println("反序列化异常"); } } catch (ioexception e) { e.printstacktrace(); system.out.println("系统异常"); } } catch (filenotfoundexception e) { e.printstacktrace(); system.out.println("文件异常"); } finally { try { fis.close(); ois.close(); } catch (ioexception e) { e.printstacktrace(); system.out.println("系统异常"); } } } } 结果: 开始序列化 序列化完成 开始反序列化 person [age=18, name=[张三, 李四]] 反序列化结束 调用fisdemo.java后,可以看到序列化结果为(如下图):
五、file类
1、定义:
是文件和目录的路径名的抽象表示。
file类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。
注意:file能创建、删除文件,但不能改变文件里的内容。
格式为: file file = new file("src" + file.separator + "demo.txt"); file.separator表示斜杠(正斜杠、反斜杠)。 或者 file file = new file("src/demo.txt");
2、方法:
(1)文件、目录的创建方法
boolean createnewfile() 不存在返回true 存在返回false。需要抛异常throws ioexception。
boolean mkdir() 创建目录
boolean mkdirs() 创建多级目录
(2)文件删除方法
boolean delete() 删除文件或者文件夹(文件夹必须为空才可以被删除,即每次删除单个文件或文件夹)
void deleteonexit() 文件使用完成后删除
(3)文件移动方法
boolean renameto(file f) 文件改名(移动)
(4)判断方法
boolean canexecute() 判断文件是否可执行
boolean canread() 判断文件是否可读
boolean canwrite() 判断文件是否可写
boolean exists() 判断文件是否存在
boolean isdirectory() 判断是否为文件夹
boolean isfile() 判断是否为文件
boolean ishidden() 判断是否隐藏
boolean isabsolute() 判断是否是绝对路径(文件不存在也能判断)
(5)获取方法
string getname() 用于获取file表示的文件名
string getpath() 获取路径
string getabsolutepath() 获取绝对路径
string getparent() 获取父目录,如果没有父目录返回null
long lastmodified() 获取文件最后一次修改的时间,是个毫秒值
long length() 获取文件所占用的字节量。
string[] list() 获得文件(夹)名列表
string[] list(filenamefilter filter) 获得文件(夹)名列表(带过滤条件)
file[] listfiles() 获得子文件(夹)数组
file[] listfiles(filenamefilter filter) 获得子文件(夹)数组(带过滤条件)
举例;(获取当前目录所在的所有文件) import java.io.file; import java.io.filefilter; import java.io.file; import java.io.filefilter; //自定义过滤器 class myfilter implements filefilter { // 继承filefilter需要重写accept方法 @override public boolean accept(file file) { return file.getname().endswith(".txt"); } } public class test { public static void main(string[] args) { file dir = new file("src/proxydemo"); // 不使用过滤器,则输出所有抽象路径名数组 if (dir.isdirectory()) { // 是目录 file[] subs = dir.listfiles(); system.out.println("不使用过滤器,文件个数为:" + subs.length); for (file sub : subs) { system.out.println(sub.getname() + " ,长度" + sub.length()); } } system.out.println(); system.out.println(); // 使用过滤器,输出符合条件的抽象路径名数组 if (dir.isdirectory()) { myfilter filter = new myfilter(); file[] subs = dir.listfiles(filter); system.out.println("使用过滤器, 文件个数为: " + subs.length); for (file sub : subs) { system.out.println(sub.getname() + " ,长度" + sub.length()); } } } } 举例: (创建多级目录下的一个文件) 创建文件时,需要先判断其目录是否存在,如果不存在目录,创建时会报错。 import java.io.file; import java.io.ioexception; public class test{ public static void main(string[] args) throws ioexception{ file file = new file("aa" + file.separator + "b" + file.separator + "c" + file.separator + "d.txt"); file parent = file.getparentfile(); //不存在路径时,需创建,否则会报错 if(!parent.exists()) { parent.mkdirs(); } //如果文件不存在,则创建 if(!file.exists()) { file.createnewfile(); system.out.println("文件创建成功!"); }else { system.out.println("文件已存在!"); } } } 举例:(删除给定文件或多级目录) 删除多级目录时,可以使用delete删,但是delete只能删除单个文件或目录。 所以,如果删除某个目录a下还有目录b,则需进入目录b删除其所有内容,若存在c目录,同理删除,可以采用递归实现。 import java.io.file; public class test{ public static void main(string[] args){ file file = new file("a"); deletefile(file); system.out.println("删除成功"); } //递归删除,如果某目录下还有目录,则进入目录继续判断,从最后一层开始往上删。 public static void deletefile(file file) { if(file.isdirectory()) { file[] subs = file.listfiles(); for(file sub : subs) { deletefile(sub); } } file.delete(); } }
六、randomaccessfile类
1、规则:
(1)使用该类可以读取文件里的内容。
(2)该类基于指针的操作,总是在当前指针的位置读写字节。
(3)对文件有两种访问方式,一个只读模式(r),一个读写模式(rw)。
2、构造方法:
(1)randomaccessfile(file file, string mode)
(2)randomaccessfile(string pathname, string mode).
注:pathname指的是文件的路径。mode指的是r或者rw。
3、普通方法:
(1)void write(int n),向文件中写东西,只写一个字节,低八位。从文件最开始的地方开始写。
(2)void write(byte[] b) ,向文件中写入字节数组。
(3) void write(byte[] b, int start, int len),指从start处开始,连续写入len个字节。
(4)void writeint(int num); 连续写入四个字节,写入一个完整int值。
(5)void writedouble(double num); 写入一个完整double值。
(6)int read();从文件中读东西,只读一个字节,低八位。通常返回一个不为-1的的值,若返回-1,则表示读取到文件的末尾。
(7)int read(byte[] b),从文件中一次读出多个字节,返回的是实际读取的字节数。
(8)long getfilepointer();获取当前指针位置
(9)void seek(long position);指定指针所在位置,从指定位置进行读写操作。
(10)int skipbytes(int n); 尝试跳过n个字节,返回实际跳过字节数。
(11)void close(); 关闭流。
举例: 使用randomaccessfile实现文件的复制: 步骤: 1、创建一个randomaccessfile ,用于读(r)。 2、创建一个randomaccessfile,用于写(rw)。 3、循环读写操作。 4、关闭两个输入输出流。 import java.io.ioexception; import java.io.randomaccessfile; public class test { public static void main(string[] args) throws ioexception { // 先创建两个流,用于读取以及写入数据 randomaccessfile rafwrite = new randomaccessfile("a.txt", "rw"); randomaccessfile rafread = new randomaccessfile("copy.txt", "rw"); // 使用getbytes(),将字符串转为字节数组。 // getbytes("utf-8")支持重载方法,使用指定编码集转为字节数组 string str = "安徽师范大学"; byte[] b = str.getbytes("utf-8"); // 批量写入数据,此时指针位于文件末尾 rafwrite.write(b); // 由于randomaccessfile基于指针操作,需将指针移到指定位置。 rafwrite.seek(0); int d = -1; // 每次循环读一个字节,并写一个字节 while ((d = rafwrite.read()) != -1) { rafread.write(d); } // 读出复制后的数据,先将指针移至指定位置 rafread.seek(3); // 读数据由于读出的是字节,需要将其转为字符串输出 byte[] r = new byte[10240]; int len = rafread.read(r); // 使用重载方法,也可以去掉utf-8这个参数,根据实际情况可能造成乱码问题 string str1 = new string(r, "utf-8"); system.out.println(str1); // 输出 徽师范大学,utf-8中中文占三个字节,gbk中占两个字节。 rafwrite.close(); rafread.close(); } }
七、properties文件读取
1、使用properties类读取文件
假定在src目录下有一个配置文件file.properties 文件内容如下: name = lyh pwd = 123456 import java.io.ioexception; import java.io.inputstream; import java.util.properties; public class test { public static void main(string[] args) throws ioexception { inputstream is = classloader.getsystemresourceasstream("file.properties"); properties properties = new properties(); properties.load(is); system.out.println(properties.getproperty("name")); } }
2、使用resourcebundle类读取文件
假定在src目录下有一个配置文件file.properties 文件内容如下: name = lyh pwd = 123456 resourcebundle resourcebundle = resourcebundle.getbundle("file"); system.out.println(resourcebundle.getstring("pwd"));
举例: import java.io.ioexception; import java.io.inputstream; import java.util.properties; import java.util.resourcebundle; public class test { public static void main(string[] args) throws ioexception { inputstream is = classloader.getsystemresourceasstream("file.properties"); properties properties = new properties(); properties.load(is); system.out.println(properties.getproperty("name")); resourcebundle resourcebundle = resourcebundle.getbundle("file"); system.out.println(resourcebundle.getstring("pwd")); } } 输出: lyh 123456
未完待续...........................................
推荐阅读
-
JAVA常用基础API(经典实例代码)
-
Java基础--常用API--IO流相关API
-
荐 Java语言基础之JDK1.8新特性(Lambda表达式、函数式接口、Stream流、新的日期API)
-
Java基础--常用API--java.lang.Object
-
java基础(15):常用API(Object、String、StringBuffer)
-
java基础常用API之String
-
Java基础--常用API--集合类相关API
-
Java基础--常用API--IO流相关API
-
Java基础常用API(转载)
-
荐 Java语言基础之JDK1.8新特性(Lambda表达式、函数式接口、Stream流、新的日期API)