黑马程序员——Java基础---IO流(File类、Properties类、其他流)
2014-11-25 13:05
721 查看
------- android培训、java培训、java学习型技术博客、期待与您交流!
----------
第一讲 File类
一、简述
File类:文件和目录路径名的抽象表现形式。
作用:
用来将文件或者文件夹封装成对象。方便于对文件或文件夹的属性信息进行操作。
特点:
流只能操作数据,而想要操作数据被封装的文件的信息必须用File对象。
File类的实例是不可变的;也就是说,一旦创建,File 对象表示的抽象路径名将永不改变
File对象可以作为参数传递给流的构造函数。
二、创建对象
三种创建方式
File file = new File("a.txt");
将a.txt封装成File对象。可以将已有的和未出现的文件或者文件夹封装成对象。
File file = newFile("e:\\abc","b.txt");
将文件所在目录路径和文件一起传入,指定文件路径。
File f = new File("e:\\abc"); File file = new File(f,"c.txt");
将文件目录路径封装成对象。再创建文件对象。降低了文件于父目录的关联性。
三、常见方法:
创建:
boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false.
和输出流不一样,输出流对象一建立就创建文件,而文件已经存在,会覆盖。
boolean mkdir():创建文件夹。
boolean mkdirs():创建多层文件夹。
删除:
boolean delete(): 删除失败返回false.
void deleteOnExit():在程序退出时删除指定文件。
判断:
booelean canExecute():判断文件是否可执行。
boolean exists(): 判断文件或目录是否存在。
boolean isFile():判断是否是文件。
boolean isDirectory():判断是否是目录。
在判断文件对象是否是文件或者是目录时,必须要先判断该文件对象封装的内容是否存在。通过exists判断。
boolean isHidden():判断是否是隐藏文件。
boolean isAbsolute():判断是否是绝对路径。
获取信息:
String getName():获取文件名。
String getPath():获取文件相对路径。
String getParent():获取文件父目录。该方法返回的是绝对路径中的父目录。如果获取的是相对路径,返回null。如果相对路径中有上一层目录,那么该目录就是返回结果。
File getAbsoluteFile():获取文件绝对路径并将其封装成对象。
String getAbsolutePath():获取文件绝对路径。
long lastModified():获取文件最后一次修改时间。
long length(): 获取文件大小。
File.pathSeparator:返回当前系统默认的路径分隔符,windows默认为 “;”。
File.Separator:返回当前系统默认的目录分隔符,windows默认为 “\”。
重命名:
boolean renameTo():将文件重命名,并转移到制定目录下。
获取计算机的盘符:
File[] files = File.listRoots();
for (File f:files){
System.out.println(f);
}
String[] list()方法:
当list方法所属对象是文件时而不是目录时,返回数组为null,调用list方法的File对象必须是封装的一个目录,而且该目录必须存在。
例如:获取C盘下当前所有的文件夹以及文件的名称(包含隐藏文件)。
File f = new File("c:\\");
//File f = new File("c:\\abc.java");
String[] names = f.list();
for (String name:names){
System.out.println(name);
}
String[] list(FileNameFilter,filter)
返回满足过滤器的文件或目录。
文件过滤器 FileNameFilter 接口,接口中只有一个返回值为boolean 型的accept()方法。
例如:用匿名内部类的方式来进行文件过滤:返回E盘下mp3文件:
File dir = new File("E:\\");
String[] arr = dir.list(new FilenameFilter()
{
public boolean accept(File dir,String name)
{
return name.endsWith(".mp3");
}
});
//E盘下文件。
System.out.println("len:"+arr.length);
for (String name: arr){
System.out.println(name);
}
注:list()方法 只返回当前文件目录下的文件及目录的名称。
File[] listFiles()
返回当前目录下的文件以及文件夹的对象。
例如:获取当前目录下的文件及文件夹名称及长度。
File dir = new File("E:\\");
File[] files = dir.listFiles();
for (File f : files){
System.out.println(f.getName() +"::"+f.length());
}
File[] listFiles(FileNameFilter,filter)返回满足过滤器的文件或目录。
练习:删除一个带内容的目录
删除原理:在Windows中,删除目录从里面往外删除的。既然是从里往外删除,就需要用到递归。
注:在删除系统盘时,有些是删不掉的。因为有些隐藏目录Java无法访问。无法访问就导致返回数组为空,会出现空指针异常。
系统中有些文件看上去是文件实际是目录,看上去是目录实际上是文件。没有扩展名,会出现空指针异常,导致程序停止。
四、递归
什么是递归:
当一个功能被重复使用,而每一次使用该功能时的参数不确定,都由上次的功能元素结果来确定。
简单说:功能内部又用到该功能,但是传递的参数值不确定。(每次功能参与运算的未知内容不确定)。
其实递归就是在栈内存中不断的加载同一个函数。
递归的注意事项:
一定要定义递归的条件。限定条件,程序必须能够结束。
递归的次数不要过多。容易出现 StackOverflowError 栈内存溢出错误。
原因:当调用函数时会在栈内存中开辟空间,如果调用的次数过多,函数在栈内存中创建的空间就越大,函数没有执行结束,内存空间得不到释放,导致内存溢出。
练习:
第二讲 Properties类
一、简述
Properties类是Hashtable的子类。也就是说它具备map集合的特点。而且它里面存储的键值对都是字符串,不需要泛型。是集合中和IO技术相结合的集合容器。
特点:
一般用于键值对形式的配置文件。
在加载数据时,需要数据有固定格式:键=值。
可以持久化存储数据。
二、特有方法
设置
Object setProperty(String key,String value);
设置键和值,调用Hashtable的方法put
获取
String getProperty(String key) 指定key搜索value
Set<String> stringPropertyName() 返回属性列表的键集,存入Set集合
加载流和存入流
void load(InputStream ism) 从输入字节流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
void load(Readerreader) 从输入字符流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
void list(PrintStream out) 将属性列表输出到指定的输出流
void store(OutputStreamout,String comments) 对应load(InputStream ) 将属性列表(键值对)写入输出流。comments属性列表的描述。
void store(Writerwriter, String comments); 对应load(Reader)将属性列表(键值对)写入输出流。comments属性列表的描述。
练习: 用于记录应用程序运行次数。如果使用次数已到,那么给出注册提示。
第三讲 其他流
一、打印流
打印流:
包括PrintStream PrintWriter
该流提供了特有的打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:PrintStream
构造函数可以接受的参数类型:
File对象,File。
字符串路径,String.
自节输出流,OutputStream。
字符打印流:PrintWriter
构造函数可以接受的参数类型:
file对象,File。
字符串路径,String.
自节输出流,OutputStream。
字符输出流,Writer。
注:PrintWriter(OutputStream out,boolean autoFlush),autoFlush,如果为true,println、printf或format方法将刷新缓冲区。
练习:
异常日志
在程序使用过程当中,程序出现问题是不希望打印给用户看到的,因此,创建程序的异常日志,将出现的问题存储,方便程序员对程序进行修改。
示例:
步骤:
创建Properties对象,接收System类的getProperties()获取的系统信息。
将信息输出到指定输出流中
用Properties对象的list(PrintStream out)
将输出流中数据存入指定文件中
new PrintStream("sysout.txt")
二、 序列流 (SequenceInputStream)
作用:对多个流进行合并。
构造函数:
SequenceInputStream(InputStream s1,InputStream s2)
SequenceInputStream(Enumeration<? extends InputStream> e)
常见合并多个流文件步骤
创建集合,并将流对象添加进集合
创建Enumeration对象,将集合元素加入。
创建SequenceInputStream对象,合并流对象
创建写入流对象,FileOutputStream关联写入文件
利用SequenceInputStream对象和FileOutputStream对象读数据进行反复读写操作。
练习:文件的切割与合并
三、对象的序列化:
对象的持久化存储(序列化)
对象本身存在于堆内存中,当程序结束后,内存中的垃圾回收,对象也就消失了。
用流将对内存中的对象存储在硬盘上,叫做对象的持久化存储。使用到的类:ObjectInputStream,ObjectOutputStream。
被操作的对象需要实现Serializable接口。
目的:将一个具体的对象进行持久化,写入到硬盘上。
注:
对象中静态数据不能被序列化,因为静态数据不在堆内存中,是存储在静态方法区中。
用transient关键字修饰变量,可以让非静态数据不被序列化。
Serializable接口:
用于启动对象的序列化功能,可以强制让指定类具备序列化功能,该接口中没有成员,这是一个标记接口。
这个标记接口用于给序列化类提供UID。这个uid是依据类中的成员的数字签名进行运行获取的。
如果不需要自动获取一个uid,可以在类中,手动指定一个名称为serialVersionUID id号。
"serialVersionUID"的字段(该字段必须是静态 (static)、最终 (final)的 long 型字段)。
如: public static final long serialVersionUID = 42L;
依据编译器的不同,或者对信息的高度敏感性。最好每一个序列化的类都进行手动显示的UID的指定。
写入流对象:
创建对象写入流,与文件关联,即传入目的。
通过写入writeObject(Object obj)方法,将对象作为参数传入,即可写入文件。
读取流对象
创建对象读取流,与文件关联,即传入源。
通过readObject()方法,读取文件中的对象,并返回这个对象。
四、管道流:
管道流:PipedInputStream。PipedOutputStream。
特点:
输入输出可以直接进行连接,不用再借助数组或集合等容器进行临时存储。connect()方法,链接管道输入流和管道读取流。
通过结合线程使用。管道读取流可以读取管道写入流写入的数据。
注:因为read方法是阻塞式的,没有数据的read方法会让线程等待。使用单线程,先执行read,会发生死锁,所以需要使用多线程技术。
通常,数据由某个线程写入PipedOutputStream对象,并由其他线程从连接的 PipedInputStream 读取。
一般操作步骤:
要先创建一个读和写的两个类,实现Runnable接口,因为是两个不同的线程,覆盖run方法,注意,需要在内部处理异常。
创建两个管道流,并用connect()方法将两个流连接
创建读写对象,并传入两个线程内,并start执行。
练习:
五、RandomAccessFile类
作用:可以实现数据的分段写入。(下载软件原理,多线程下载)
该类不算是IO体系中子类,而是直接继承自Object。但是它是IO包中成员。因为它具备读和写的功能。
特点:
该对象既可以读取,也可以写入。
对象内部封装了一个byte数组,而且通过指针对数组的元素进行操作。,
该对象可以通过getFilePointer()方法获取指针位置。同时可以通过seek()方法改变指针的位置。
该对象操作的源和目的必须是文件。
该对象内部封装了字节输入流和字节输出流。
完成读写原理:
内部封装了字节输入流和字节输出流。byte数组操作的是字节。
通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式:只读r,读写rw等。,
如果模式为只读 r 。不会创建文件,会去读取一个已存在的文件。
如果该文件不存在,则会出现异常。
如果模式为rw。操作的文件不存在,会自动创建,如果存在则不会覆盖。
随机访问文件,自身具备读写的方法。
通过skipBytes(int x),seek(int x);来达到随机访问。
skipBytes(int x),调整对象中指针,只能向后,不能向前。
seek(int x) 调整对象中指针,可以前后移动。
注:在实现随机数据读取时,数据最好有规律。
练习:
六、操作基本数据类型的流对象
操作基本数据类型的流对象:DataInputStream,DataOutputStream
可用于操作基本数据类型的流对象,包含读写各种基本数据类型的方法。
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(234);
dos.writeBoolean(true);
dos.writeDouble(9867.453);
dos.close();
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
int num = dis.readInt();
boolean b = dis.readBoolean();
double d = dis.readDouble();
System.out.println("num =" +num);
System.out.println("b =" + b);
System.out.println("d =" + d);
dis.close();
注:
String readUTF();//对应writeUTF,读取以UTF-8修改版编码写入的字符串
writeUTF(String str);//以与机器无关方式使用UTF-8修改版编码将一个字符串写入基础输出流。
七、 操作字节数组的流对象。
操作字节数组的流:ByteArrayInputStream和ByteArrayOutputStream
ByteArrayInputStream: 在构造的时候,需要接收数据源,而且数据源是一个字节数组。
ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经封装了一个可变长度的字节数组。这就是数据目的地。
因为这两个流对象操作的都是数组并没有使用系统资源,所以不用进行close关闭。即使关闭后,仍可调用。
内部包含缓冲区,相当于以内存作为流操作源和目的,不会产生任何IO异常。
对象中封装了数组。
特有方法:
ByteArrayOutputStream中:
writeTo(OutputStream out);
将此 byte 数组输出流的全部内容写入到指定的输出流参数中,这与使用out.write(buf,
0, count)调用该输出流的 write 方法效果一样。
因为这个方法用到了字节输出流,需要抛IO异常,也是字节数组流中唯一需要抛异常的方法。
int size();//当前缓冲区的大小
String toString();使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。
对应的字符数组和字符串
字符数组流:CharArrayReader和CharArrayWriter
字符串流: StringReader和StringWriter
------- android培训、java培训、java学习型技术博客、期待与您交流!
----------
----------
第一讲 File类
一、简述
File类:文件和目录路径名的抽象表现形式。
作用:
用来将文件或者文件夹封装成对象。方便于对文件或文件夹的属性信息进行操作。
特点:
流只能操作数据,而想要操作数据被封装的文件的信息必须用File对象。
File类的实例是不可变的;也就是说,一旦创建,File 对象表示的抽象路径名将永不改变
File对象可以作为参数传递给流的构造函数。
二、创建对象
三种创建方式
File file = new File("a.txt");
将a.txt封装成File对象。可以将已有的和未出现的文件或者文件夹封装成对象。
File file = newFile("e:\\abc","b.txt");
将文件所在目录路径和文件一起传入,指定文件路径。
File f = new File("e:\\abc"); File file = new File(f,"c.txt");
将文件目录路径封装成对象。再创建文件对象。降低了文件于父目录的关联性。
三、常见方法:
创建:
boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false.
和输出流不一样,输出流对象一建立就创建文件,而文件已经存在,会覆盖。
boolean mkdir():创建文件夹。
boolean mkdirs():创建多层文件夹。
删除:
boolean delete(): 删除失败返回false.
void deleteOnExit():在程序退出时删除指定文件。
判断:
booelean canExecute():判断文件是否可执行。
boolean exists(): 判断文件或目录是否存在。
boolean isFile():判断是否是文件。
boolean isDirectory():判断是否是目录。
在判断文件对象是否是文件或者是目录时,必须要先判断该文件对象封装的内容是否存在。通过exists判断。
boolean isHidden():判断是否是隐藏文件。
boolean isAbsolute():判断是否是绝对路径。
获取信息:
String getName():获取文件名。
String getPath():获取文件相对路径。
String getParent():获取文件父目录。该方法返回的是绝对路径中的父目录。如果获取的是相对路径,返回null。如果相对路径中有上一层目录,那么该目录就是返回结果。
File getAbsoluteFile():获取文件绝对路径并将其封装成对象。
String getAbsolutePath():获取文件绝对路径。
long lastModified():获取文件最后一次修改时间。
long length(): 获取文件大小。
File.pathSeparator:返回当前系统默认的路径分隔符,windows默认为 “;”。
File.Separator:返回当前系统默认的目录分隔符,windows默认为 “\”。
重命名:
boolean renameTo():将文件重命名,并转移到制定目录下。
获取计算机的盘符:
File[] files = File.listRoots();
for (File f:files){
System.out.println(f);
}
String[] list()方法:
当list方法所属对象是文件时而不是目录时,返回数组为null,调用list方法的File对象必须是封装的一个目录,而且该目录必须存在。
例如:获取C盘下当前所有的文件夹以及文件的名称(包含隐藏文件)。
File f = new File("c:\\");
//File f = new File("c:\\abc.java");
String[] names = f.list();
for (String name:names){
System.out.println(name);
}
String[] list(FileNameFilter,filter)
返回满足过滤器的文件或目录。
文件过滤器 FileNameFilter 接口,接口中只有一个返回值为boolean 型的accept()方法。
例如:用匿名内部类的方式来进行文件过滤:返回E盘下mp3文件:
File dir = new File("E:\\");
String[] arr = dir.list(new FilenameFilter()
{
public boolean accept(File dir,String name)
{
return name.endsWith(".mp3");
}
});
//E盘下文件。
System.out.println("len:"+arr.length);
for (String name: arr){
System.out.println(name);
}
注:list()方法 只返回当前文件目录下的文件及目录的名称。
File[] listFiles()
返回当前目录下的文件以及文件夹的对象。
例如:获取当前目录下的文件及文件夹名称及长度。
File dir = new File("E:\\");
File[] files = dir.listFiles();
for (File f : files){
System.out.println(f.getName() +"::"+f.length());
}
File[] listFiles(FileNameFilter,filter)返回满足过滤器的文件或目录。
练习:删除一个带内容的目录
删除原理:在Windows中,删除目录从里面往外删除的。既然是从里往外删除,就需要用到递归。
注:在删除系统盘时,有些是删不掉的。因为有些隐藏目录Java无法访问。无法访问就导致返回数组为空,会出现空指针异常。
系统中有些文件看上去是文件实际是目录,看上去是目录实际上是文件。没有扩展名,会出现空指针异常,导致程序停止。
import java.io.*; class RemoveDir { public static void main(String[] args) { File dir = new File("H:\\Exercise"); removeDir(dir); } public static void removeDir(File dir) { File[] files = dir.listFiles(); for (int x = 0;x < files.length;x++) { if(files[x].isDirectory()) removeDir(files[x]); else System.out.println(files[x].toString()+"::"+files[x].delete()); } System.out.println(dir+"::dir::"+dir.delete()); } }
四、递归
什么是递归:
当一个功能被重复使用,而每一次使用该功能时的参数不确定,都由上次的功能元素结果来确定。
简单说:功能内部又用到该功能,但是传递的参数值不确定。(每次功能参与运算的未知内容不确定)。
其实递归就是在栈内存中不断的加载同一个函数。
递归的注意事项:
一定要定义递归的条件。限定条件,程序必须能够结束。
递归的次数不要过多。容易出现 StackOverflowError 栈内存溢出错误。
原因:当调用函数时会在栈内存中开辟空间,如果调用的次数过多,函数在栈内存中创建的空间就越大,函数没有执行结束,内存空间得不到释放,导致内存溢出。
练习:
import java.io.*; class FileDemo3 { public static void main(String[] args) { File dir = new File("G:\\360Downloads"); showDir(dir); toBin(8); int n = getSum(10); System.out.println("n = "+ n); } //输出目录下所有文件夹及文件 public static void showDir(File dir) { System.out.println(dir); File[] files = dir.listFiles(); for (int x = 0;x < files.length;x++) { if(files[x].isDirectory()) showDir(files[x]); else System.out.println(files[x]); } } //求一个整数的2进制 public static void toBin(int num) { /* while (num>0) { System.out.println(num%2); num = num / 2; } */ if (num>0) { toBin(num/2); System.out.println(num%2); } } public static int getSum(int n) { //递归求和 if (n==1) return 1; return n+getSum(n-1); } }
第二讲 Properties类
一、简述
Properties类是Hashtable的子类。也就是说它具备map集合的特点。而且它里面存储的键值对都是字符串,不需要泛型。是集合中和IO技术相结合的集合容器。
特点:
一般用于键值对形式的配置文件。
在加载数据时,需要数据有固定格式:键=值。
可以持久化存储数据。
二、特有方法
设置
Object setProperty(String key,String value);
设置键和值,调用Hashtable的方法put
获取
String getProperty(String key) 指定key搜索value
Set<String> stringPropertyName() 返回属性列表的键集,存入Set集合
加载流和存入流
void load(InputStream ism) 从输入字节流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
void load(Readerreader) 从输入字符流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
void list(PrintStream out) 将属性列表输出到指定的输出流
void store(OutputStreamout,String comments) 对应load(InputStream ) 将属性列表(键值对)写入输出流。comments属性列表的描述。
void store(Writerwriter, String comments); 对应load(Reader)将属性列表(键值对)写入输出流。comments属性列表的描述。
练习: 用于记录应用程序运行次数。如果使用次数已到,那么给出注册提示。
/* 练习:用于记录应用程序运行次数。如果使用次数已到,那么给出注册提示。 分析: 很容易想到的是:计数器。 可是该计数器定义在程序中,随着程序的运行而在内存中存在并进行了自增。可是随着该应用程序的退出, 该计数器也在内存中消失了。下一次再启动该程序,又重新开始从0记数。这样不是我们想要的。 程序即使结束,该计数器的值也存在。下一次程序启动后会先加载该计数器的值并加1后再重新存储起来。 所以要建立一个配置文件,用于记录该软件的使用次数。该配置文件使用键值对的形式。这样便于阅读数据,并操作数据。 键值对数据是map集合。数据是以文件形式存储,使用IO技术。那么map+IO -->Properties。 思路:1、用读取流关联文本信息文件。如果存在则读取,如果不存在,则创建 2、每次运行,将文件数据存入集合中,读取值,判断次数,如果小于等于5次,则次数增加1次,如果大于则输出提示信息。 3、将值小于等于5次的信息数据存入文件中 */ import java.io.*; import java.util.*; class RunCount { public static void main(String[] args) throws IOException { Properties prop = new Properties(); // 创建配置文件 File file = new File("count.ini"); // 如果文件不存在就创建一个文件 if(!file.exists()) file.createNewFile(); //创建流对象与文件相关联 FileInputStream fis = new FileInputStream("count.ini"); //将流中的数据加载进集合。 prop.load(fis); //用于记录程序运行次数 int count = 0; //根据键获取值 String value = prop.getProperty("time"); if(value != null) { //如果值不为空,将值转化成整数付给计数器。 count =Integer.parseInt(value); if(count>=5) { System.out.println("您好,使用次数已到,请注册"); return ; } } count++; //设置键值 prop.setProperty("time",count+""); //将设置的键值保存到文件中 FileOutputStream fos = new FileOutputStream(file); prop.store(fos,"setTime"); //关闭流资源 fos.close(); fis.close(); } }
第三讲 其他流
一、打印流
打印流:
包括PrintStream PrintWriter
该流提供了特有的打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:PrintStream
构造函数可以接受的参数类型:
File对象,File。
字符串路径,String.
自节输出流,OutputStream。
字符打印流:PrintWriter
构造函数可以接受的参数类型:
file对象,File。
字符串路径,String.
自节输出流,OutputStream。
字符输出流,Writer。
注:PrintWriter(OutputStream out,boolean autoFlush),autoFlush,如果为true,println、printf或format方法将刷新缓冲区。
练习:
import java.io.*; class PrintStreamDemo { public static void main(String[] args) throws IOException { //键盘录入 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); //创建打印流对象,指定目的地 //PrintWriter out = new PrintWriter(System.out); // 创建打印流对象,指定目文件相关联,并加入缓冲技术 PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("a.txt")),true); String line = null; while ((line = bufr.readLine())!=null) { if("over".equals(line)) break; //将数据写入缓冲区 //out.write(line); //将数据从缓冲区刷新到目的地 //out.flush(); // 将数据写入缓冲区,从缓冲区刷新到目的地 out.println(line); } //关闭流 out.close(); bufr.close(); } }
异常日志
在程序使用过程当中,程序出现问题是不希望打印给用户看到的,因此,创建程序的异常日志,将出现的问题存储,方便程序员对程序进行修改。
示例:
import java.io.*; import java.util.*; import java.text.*; class ExceptionInfo { public static void main(String[] args) throws IOException { try { int[] arr = new int[2]; System.out.println(arr[3]); } catch (Exception e) { try { //创建时间对象 Date date = new Date(); //将时间格式化 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss"); String s =sdf.format(date); //创建输出对象与文件相关联 PrintStream ps = new PrintStream("exception.log"); //输出异常发生时间 ps.println(s); //设置输出设备为文件 System.setOut(ps); } catch (Exception ex) { throw new RuntimeException("日志文件创建失败"); } e.printStackTrace(System.out); } } }获取系统信息
步骤:
创建Properties对象,接收System类的getProperties()获取的系统信息。
将信息输出到指定输出流中
用Properties对象的list(PrintStream out)
将输出流中数据存入指定文件中
new PrintStream("sysout.txt")
import java.util.*; import java.io.*; class SystemInfo { public static void main(String[] args) throws IOException { Properties prop = System.getProperties(); //将系统信息输出在控制台 //System.out.println(prop); //prop.list(System.out); //将系统属性信息存储到关联文件中 prop.list(new PrintStream("sysout.txt")); } }
二、 序列流 (SequenceInputStream)
作用:对多个流进行合并。
构造函数:
SequenceInputStream(InputStream s1,InputStream s2)
SequenceInputStream(Enumeration<? extends InputStream> e)
常见合并多个流文件步骤
创建集合,并将流对象添加进集合
创建Enumeration对象,将集合元素加入。
创建SequenceInputStream对象,合并流对象
创建写入流对象,FileOutputStream关联写入文件
利用SequenceInputStream对象和FileOutputStream对象读数据进行反复读写操作。
/* 练习:合并多个.txt文件 */ import java.io.*; import java.util.*; class SequenceDemo { public static void main(String[] args) throws IOException { Vector<FileInputStream> v = new Vector<FileInputStream>(); v.add(new FileInputStream("E:\\1.txt")); v.add(new FileInputStream("E:\\2.txt")); v.add(new FileInputStream("E:\\3.txt")); Enumeration<FileInputStream> en = v.elements(); //创建序列流对象接收Enumeration对象 SequenceInputStream sis = new SequenceInputStream(en); //创建输出流对象与文件相关联 FileOutputStream fos = new FileOutputStream("E:\\4.txt"); //创建缓冲区 byte[] buf = new byte[1024]; int len = 0; while ((len =sis.read(buf))!=-1) { //将缓冲区读取的数据写到目的地 fos.write(buf,0,len); } //关闭流资源 fos.close(); sis.close(); } }
练习:文件的切割与合并
import java.io.*; import java.util.*; class SplitMergeFile { public static void main(String[] args) throws IOException { //splitFile(); merge(); } //切割 public static void splitFile()throws IOException { //创建读取流流对象与文件相关联 FileInputStream fis = new FileInputStream("E:\\1.bmp"); //创建写入流对象 FileOutputStream fos = null; //创建缓冲区 byte[] buf = new byte[1024*1024]; int len = 0; //对切割次数进行标记 int count = 1; //将切割缓冲区数据读取并写入目的地 while ((len = fis.read(buf))!=-1) { fos = new FileOutputStream("E:\\splitfiles\\"+(count++)+".part"); fos.write(buf,0,len); fos.close(); } fis.close(); } //合并 public static void merge()throws IOException { //创建集合对象 ArrayList<FileInputStream> al = new ArrayList<FileInputStream> (); //创建流对象与文件相关联并将流对象添加到集合中 for (int x = 1;x<=3 ;x++) { al.add(new FileInputStream("E:\\splitfiles\\"+ x +".part")); } //创建迭代器 final Iterator<FileInputStream> it = al.iterator(); //枚举的匿名内部类来实现迭代 Enumeration<FileInputStream> en = new Enumeration<FileInputStream>() { //复写 Enumeration方法 public boolean hasMoreElements() { return it.hasNext(); } public FileInputStream nextElement() { return it.next(); } }; //c创建序列流对象接收Enumeration对象 SequenceInputStream sis = new SequenceInputStream(en); //创建输出流对象与文件相关联 FileOutputStream fos = new FileOutputStream("E:\\splitfiles\\0.bmp"); //创建缓冲区 byte[] buf = new byte[1024*1024]; int len = 0; while ((len = sis.read(buf))!= -1) { //将缓冲区读取的数据写到目的地 fos.write(buf,0,len); } //关闭流资源 fos.close(); sis.close(); } }
三、对象的序列化:
对象的持久化存储(序列化)
对象本身存在于堆内存中,当程序结束后,内存中的垃圾回收,对象也就消失了。
用流将对内存中的对象存储在硬盘上,叫做对象的持久化存储。使用到的类:ObjectInputStream,ObjectOutputStream。
被操作的对象需要实现Serializable接口。
目的:将一个具体的对象进行持久化,写入到硬盘上。
注:
对象中静态数据不能被序列化,因为静态数据不在堆内存中,是存储在静态方法区中。
用transient关键字修饰变量,可以让非静态数据不被序列化。
Serializable接口:
用于启动对象的序列化功能,可以强制让指定类具备序列化功能,该接口中没有成员,这是一个标记接口。
这个标记接口用于给序列化类提供UID。这个uid是依据类中的成员的数字签名进行运行获取的。
如果不需要自动获取一个uid,可以在类中,手动指定一个名称为serialVersionUID id号。
"serialVersionUID"的字段(该字段必须是静态 (static)、最终 (final)的 long 型字段)。
如: public static final long serialVersionUID = 42L;
依据编译器的不同,或者对信息的高度敏感性。最好每一个序列化的类都进行手动显示的UID的指定。
写入流对象:
创建对象写入流,与文件关联,即传入目的。
通过写入writeObject(Object obj)方法,将对象作为参数传入,即可写入文件。
读取流对象
创建对象读取流,与文件关联,即传入源。
通过readObject()方法,读取文件中的对象,并返回这个对象。
/* 需求:将一个对象序列号,并从硬盘中读取序列化的对象 */ import java.io.*; public class ObjectStreamDemo { public static void main(String[] args) { writeObj(); readObj() ; } //将指定对象序列化到指定文件中 public static void writeObj() { ObjectOutputStream oos =null; try { //将一个对象写到文件当中, //数据不是纯文本,对文件进行操作 //选择FileOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.object")); //数据("lisi",29) 在堆内存中 被封装到Person对象中, //将Person对象写入到文件"obj.txt"中 oos.writeObject(new Person("lisi",29,"kr")); } catch (Exception e) { throw new RuntimeException("写入数据失败"); } finally{ try { if(oos!=null) oos.close(); } catch (IOException e) { throw new RuntimeException("写入关闭失败"); } } } //读取指定文件中的对象,也称反序列化 public static void readObj() { ObjectInputStream ois =null; try { //创建读取流对象,关联文件 ois = new ObjectInputStream(new FileInputStream("person.object")); //读取文件中的对象 Person p = (Person)ois.readObject(); System.out.println(p.getName()+":"+p.getAge()+":"+p.getCountry()); } catch (Exception e) { throw new RuntimeException("读取数据失败"); } finally{ try { if(ois!=null) ois.close(); } catch (IOException e) { throw new RuntimeException("读取关闭失败"); } } } } //创建Peason类,实现Serializable接口 class Person implements Serializable { //自定义serialVersionUID版本号 private static final long serialVersionUID = 42L; private String name; transient int age;//用transient修饰后age将不会进行序列化 static String country ="cn";//静态数据不会进行序列化 Person(String name,int age,String country) { this.name = name; this.age = age; this. country= country; } public String getName() { return name + ":" + age +","+id+","+ country; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public static String getCountry() { return country; } public static void setCountry(String country) { Person.country = country; } }
四、管道流:
管道流:PipedInputStream。PipedOutputStream。
特点:
输入输出可以直接进行连接,不用再借助数组或集合等容器进行临时存储。connect()方法,链接管道输入流和管道读取流。
通过结合线程使用。管道读取流可以读取管道写入流写入的数据。
注:因为read方法是阻塞式的,没有数据的read方法会让线程等待。使用单线程,先执行read,会发生死锁,所以需要使用多线程技术。
通常,数据由某个线程写入PipedOutputStream对象,并由其他线程从连接的 PipedInputStream 读取。
一般操作步骤:
要先创建一个读和写的两个类,实现Runnable接口,因为是两个不同的线程,覆盖run方法,注意,需要在内部处理异常。
创建两个管道流,并用connect()方法将两个流连接
创建读写对象,并传入两个线程内,并start执行。
练习:
import java.io.*; class Read implements Runnable { private PipedInputStream in; Read(PipedInputStream in) { this.in = in; } public void run()//覆盖run方法。异常不能抛,只能try。 { try { byte[] buf = new byte[1024]; System.out.println("读取前..没有数据,阻塞"); //阻塞式方法read,没有数据就得等,等些入数据后才执行。 int len = in.read(buf); System.out.println("读到数据..阻塞结束"); String s = new String(buf,0,len); System.out.println(s); in.close(); } catch (IOException e) { throw new RuntimeException("管道读取流失败"); } } } class Write implements Runnable { private PipedOutputStream out; Write(PipedOutputStream out) { this.out = out; } public void run() { try { System.out.println("开始写入数据,等待6秒后."); Thread.sleep(3000); out.write("piped lai la".getBytes()); out.close(); } catch (Exception e ) { throw new RuntimeException("管道输出流失败"); } } } class PipedStreamDemo { public static void main(String[] args) throws IOException { PipedInputStream in = new PipedInputStream(); PipedOutputStream out = new PipedOutputStream(); in.connect(out); Read r = new Read(in); Write w = new Write(out); new Thread(r).start(); new Thread(w).start(); } }
五、RandomAccessFile类
作用:可以实现数据的分段写入。(下载软件原理,多线程下载)
该类不算是IO体系中子类,而是直接继承自Object。但是它是IO包中成员。因为它具备读和写的功能。
特点:
该对象既可以读取,也可以写入。
对象内部封装了一个byte数组,而且通过指针对数组的元素进行操作。,
该对象可以通过getFilePointer()方法获取指针位置。同时可以通过seek()方法改变指针的位置。
该对象操作的源和目的必须是文件。
该对象内部封装了字节输入流和字节输出流。
完成读写原理:
内部封装了字节输入流和字节输出流。byte数组操作的是字节。
通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式:只读r,读写rw等。,
如果模式为只读 r 。不会创建文件,会去读取一个已存在的文件。
如果该文件不存在,则会出现异常。
如果模式为rw。操作的文件不存在,会自动创建,如果存在则不会覆盖。
随机访问文件,自身具备读写的方法。
通过skipBytes(int x),seek(int x);来达到随机访问。
skipBytes(int x),调整对象中指针,只能向后,不能向前。
seek(int x) 调整对象中指针,可以前后移动。
注:在实现随机数据读取时,数据最好有规律。
练习:
import java.io.*; class RandomAccessFileDemo { public static void main(String[] args) throws IOException { writeFile(); readFile(); } public static void readFile()throws IOException { RandomAccessFile raf = new RandomAccessFile("ran.txt","r"); //调整对象中指针。分段要有规律 //raf.seek(8*1); //跳过指针的字节数。 raf.skipBytes(8); byte[] buf = new byte[4]; raf.read(buf); String name = new String(buf); int age = raf.readInt(); System.out.println("name:"+name); System.out.println("age = "+age); raf.close(); } public static void writeFile()throws IOException { RandomAccessFile raf = new RandomAccessFile("ran.txt","rw"); raf.write("张三".getBytes()); //write方法只写出int类型的最低8位。 raf.writeInt(99); raf.write("李四".getBytes()); raf.writeInt(97); raf.close(); } //在文件随机位置写入数据 public static void writeFile_2()throws IOException { RandomAccessFile raf = new RandomAccessFile("ran.txt","rw"); raf.seek(8*3); raf.write("周七".getBytes()); raf.writeInt(103); raf.close(); } }
六、操作基本数据类型的流对象
操作基本数据类型的流对象:DataInputStream,DataOutputStream
可用于操作基本数据类型的流对象,包含读写各种基本数据类型的方法。
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(234);
dos.writeBoolean(true);
dos.writeDouble(9867.453);
dos.close();
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
int num = dis.readInt();
boolean b = dis.readBoolean();
double d = dis.readDouble();
System.out.println("num =" +num);
System.out.println("b =" + b);
System.out.println("d =" + d);
dis.close();
注:
String readUTF();//对应writeUTF,读取以UTF-8修改版编码写入的字符串
writeUTF(String str);//以与机器无关方式使用UTF-8修改版编码将一个字符串写入基础输出流。
七、 操作字节数组的流对象。
操作字节数组的流:ByteArrayInputStream和ByteArrayOutputStream
ByteArrayInputStream: 在构造的时候,需要接收数据源,而且数据源是一个字节数组。
ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经封装了一个可变长度的字节数组。这就是数据目的地。
因为这两个流对象操作的都是数组并没有使用系统资源,所以不用进行close关闭。即使关闭后,仍可调用。
内部包含缓冲区,相当于以内存作为流操作源和目的,不会产生任何IO异常。
对象中封装了数组。
特有方法:
ByteArrayOutputStream中:
writeTo(OutputStream out);
将此 byte 数组输出流的全部内容写入到指定的输出流参数中,这与使用out.write(buf,
0, count)调用该输出流的 write 方法效果一样。
因为这个方法用到了字节输出流,需要抛IO异常,也是字节数组流中唯一需要抛异常的方法。
int size();//当前缓冲区的大小
String toString();使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。
对应的字符数组和字符串
字符数组流:CharArrayReader和CharArrayWriter
字符串流: StringReader和StringWriter
import java.io.*; class ByteArrayStream { public static void main(String[] args) { //System.out.println("Hello World!"); //数据源。 ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFG".getBytes()); // 数据目的 ByteArrayOutputStream bos = new ByteArrayOutputStream(); int by = 0; while ((by = bis.read())!= -1) { bos.write(by); } System.out.println(bos.size()); System.out.println(bos.toString()); //bos.writeTo(new FileOutputStream("a.txt")); } }
------- android培训、java培训、java学习型技术博客、期待与您交流!
----------
相关文章推荐
- 黑马程序员——java基础——IO流(2)File类,IO常用流对象及IO包中其他类
- 黑马程序员_Java基础_IO流(File类和properties类相关操作)
- 黑马程序员_Java基础_IO流(File类和properties类相关操作)
- 黑马程序员——java基础拾遗之IO流(二)File 和 Properties的使用
- 黑马程序员——JAVA基础之IO流FileReader,FileWriter
- 黑马程序员——Java基础—IO流(File)
- 黑马程序员java基础之io流中的其他流
- 黑马程序员——Java基础----IO(File类、Properties类、打印流、序列流、合并流)(3)
- 黑马程序员---java基础之IO(File类及其他流对象)
- 黑马程序员--Java基础学习(IO流--File对象和Properties)第二十天
- 黑马程序员-JAVA基础-IO流之File 类
- 黑马程序员--Java基础学习之IO流之File类、Properties对象、打印流、序列流等
- 黑马程序员-JAVA基础-IO流其他类
- 黑马程序员——Java基础——File、Properties类、 打印流、序列流
- 黑马程序员-----Java基础-----File,Properties和其他IO处理流
- 黑马程序员_Java基础_IO流_File类,列出(删除)目录下内容,Properties类,付费软件提示原理
- 黑马程序员——java基础——IO流中的其他常用类
- 黑马程序员——Java基础——IO流笔记(FileReader使用示例)
- 黑马程序员--Java基础学习(其他对象和IO流)第十八天
- 黑马程序员——Java基础——File、Properties类