IO
IO,即输入输出流。这里的输入输出是相对于内存的,比如向一个文件中写东西,实为从内存写到硬盘,则为输出,反之为输入。
流的概念和作用
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
IO流的分类
根据处理数据类型的不同分为:字符流和字节流
根据数据流向不同分为:输入流和输出流
字符流和字节流
字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。 字节流和字符流的区别:
读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。
输入流和输出流
对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。
一、字符流:
1.FileWriter,FileReader:文件输出流 ,文件输入流
FileWriter 的方法:
FileWriter(String fileName):构造函数,指定需要写入的文件名。
write(String s):将字符串s写入流(所关联的文件)中,先保存在缓冲区(是的你没有看错,FileWriter有一个默认缓冲区,其实Writer类及它的子类都有默认的缓冲区,因为Writer类有flush方法),在flush时或close之前立即写入文件中。
write(char[] ch):[不推荐使用]将字符数组写入流中。
write(char[],offset,len):[推荐使用]将字符数组的一部分写入流中。数据最后一次写时可能没有写满数组,效率提高了一点点。
flush():刷新字符流缓冲区,如果该流已保存缓冲区中各种 write() 方法的所有字符,则立即将它们写入预期目标。
append(char c):将字符续写到文件中。
close():关闭此流,但在之前要调用flush方法。
FileReader的方法:
FileReader(String fileName):构造函数,指定需要读取的文件名。
int read():读取一个字符,返回它的Unicode值的十进制表示。
int read(char[] cbuf):[推荐使用]将字符读入数组。
int read(char[] cbuf,int offset,int len):[不推荐使用]将字符读入数组的一部分。不推荐因为不知道最后一次读数据的长度,无法知道数组使用的长度。
close():关闭流。
IO_01_FileWriterDemo.java
import java.io.FileWriter;
import java.io.IOException;
/**
*文件字符输出流FileWriter
*/
public class IO_01_FileWriterDemo {
//将换行符封装成一个全局常量。
private static final String LINE_SEPERATOR = System.getProperty("line.separator");
public static void main(String[] args) throws IOException {
//文件输出流,从内存中写到硬盘上
FileWriter fw = new FileWriter("a.txt");
//可以用带两个参数的构造函数,支持续写,则不覆盖原文件内容
// FileWriter fw = new FileWriter("a.txt", true);
//write会覆盖原文件内容,文件不存在则创建。
//Windows中的换行字符是\r\n
fw.write("abcdefg"+LINE_SEPERATOR);
//向文件中加入
fw.append('f');
//必须刷新,将缓冲区的数据写入到硬盘
fw.flush();
//close前会自动flush一次该流的缓冲。
}
}</span>
IO_02_FileReaderDemo.java
import java.io.FileReader;
import java.io.IOException;
public class IO_02_FileReaderDemo {
public static void main(String[] args) throws IOException {
//第二种方法read(char[])
FileReader fr = new FileReader("a.txt");
//使用read(char[])方法读取字符输入流中的数据,返回读取的字符个数,如果读完了则返回-1
char[] arr= new char[1024];
int len = fr.read(arr);
//通过String(char[],offset,count)得到读取的字符串。
System.out.println(new String(arr,0,len));
fr.close();
/*
//第一种方法read()
FileReader fr = new FileReader("a.txt");
int num = 0;//输入输出流信息传递的桥梁
while((num=fr.read()) != -1){
System.out.println(num);
}
*/
}
}</span>
IO_03_FileReader_FileWriter_Practice.java
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* 使用FileReader,FileWriter将a.txt中的内容写入b.txt中
*/
public class IO_03_FileReader_FileWriter_Practice {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt",true);
//创建字符数组作为输入流和输出流信息传递的桥梁,之前的字符ch,之后的BufferedReader,BufferedWrier缓冲区也是这个作用
char[] arr = new char[1024];
int len = 0;
while((len = fr.read(arr)) != -1){
fw.write(arr,0,len);
}
fr.close();
fw.close();
}
}</span>
2.BufferedWriter,BufferedReader输出流缓冲区,输入流缓冲区(不是必要的,可以提高效率)
BufferedWriter将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
缓冲区是装饰设计模式的体现:把原来的对象作为参数传构造时进去,对对象的功能进行增强.
装饰设计模式和继承的异同:
都能进行功能拓展,装饰模式比继承要灵活。避免了继承体系臃肿。降低了类于类之间的关系。装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。所以装饰类和被装饰类通常是都属于一个体系中的。在JAVA IO中用了很多增强 如:FileRead中read()方法 只是一个一个字节去读,为了读得更快在BufferedReader就增强了read()方法而产生了reandLine()一行一行的去读.
可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
该类提供了 newLine() 方法,它使用平台自己的行分隔符概念,此概念由系统属性line.separator 定义。并非所有平台都使用新行符 ('\n') 来终止各行。因此调用此方法来终止每个输出行要优于直接写入新行符。
通常 Writer 将其输出立即发送到底层字符或字节流。除非要求提示输出,否则建议用 BufferedWriter 包装所有其 write() 操作可能开销很高的 Writer(如 FileWriters 和 OutputStreamWriters)。例如,
PrintWriter out
= new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
将缓冲 PrintWriter 对文件的输出。如果没有缓冲,则每次调用 print() 方法会导致将字符转换为字节,然后立即写入到文件,而这是极其低效的。
BufferedWriter的方法
BufferedWriter(Writer out):创建一个使用默认大小输出缓冲区的缓冲字符输出流
close():关闭此流,但要刷新它
flush():刷新缓冲区
newLine():写入一个换行符。是BufferedWriter独有的方法。
write(String s):写入字符串
write(String s,int off,int len):写入字符串的一部分
write(char[] cbuf):写入字符数组
write(char[] cbuf,int off,int len):写入字符数组的一部分
BufferedReader的方法:
BufferedReader(Reader in):创建一个使用默认大小输出缓冲区的缓冲字符输入流
int read():读取一个字符
int read(char[] cbuf,int off,int len):读取字符数组的一部分
String readLine():读取一行(以换行符为标志)
IO_04_BufferedWriter.java
import java.io.BufferedWriter;
import java.io.FileWriter;
public class IO_04_BufferedWriter {
public static void main(String[] args) {
try {
FileWriter fw = new FileWriter("a.txt");
BufferedWriter bufw = new BufferedWriter(fw);
bufw.write("aaa");
//最好写一次刷一次
bufw.flush();
//写入换行符
bufw.newLine();
bufw.flush();
bufw.write("bbb");
bufw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
</span>
IO_05_BufferedReader_readLine.java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class IO_05_BufferedReader_readLine {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("a.txt");
BufferedReader br = new BufferedReader(fr);
String line = null;
while((line = br.readLine()) != null){
System.out.println(line);
}
}
}
</span>
IO_06_BufferedWriter_BufferedReader_Practice.java
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class IO_06_BufferedWriter_BufferedReader_Practice {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);
FileWriter fw = new FileWriter("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);
String line = null;
while((line = bufr.readLine()) != null){
bufw.write(line);
//想要和a.txt一样则需要每行写入一个换行符
bufw.newLine();
bufw.flush();
}
bufw.close();
bufr.close();
}
}
LineNumberReader可以输出行号,继承自BufferedReader,有两个方法setLineNumber(int i), int getLineNumber();可以设置和获取当前行号.输出带有行号的内容.例如
IO_07_LineNumberReader.java
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
public class IO_07_LineNumberReader {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("a.txt");
LineNumberReader lnr = new LineNumberReader(fr);
String line = null;
//设置开始的行号
lnr.setLineNumber(1000);
while((line = lnr.readLine()) != null){
System.out.println(lnr.getLineNumber()+":"+line);
}
lnr.close();
}
}
控制台输出:
1001:public class IO_05_BufferedReader_readLine {
1002: public static void main(String[] args) throws IOException {
1003: FileReader fr = new FileReader("a.txt");
1004: BufferedReader br = new BufferedReader(fr);
1005: String line = null;
1006: while((line = br.readLine()) != null){
1007: System.out.println(line);
1008: }
1009: }
1010:}
二,字节流
字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组
FileOutputStream
FileOutputStream的方法
write(byte[]):写入字节数组
write(byte[],int off,int len):写入字节数组的一部分
write(int b):写入Unicode的十进制表示的字符
FileInputStream
FileInputStream的方法
read(int i):读取该字符的Unicode的十进制表示
read(byte[]):读取该字节数组
read(byte[] int off,int len):读取字节数组的一部分
int available():返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数
IO_08_FileOutputStream.java
import java.io.FileOutputStream;
import java.io.IOException;
public class IO_08_FileOutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("a.txt");
fos.write("hahaha".getBytes());
//字节流直接读取字节,不使用缓冲机制,不需要刷新
fos.close();
}
}
IO_09_FileInputStream.java
import java.io.FileInputStream;
import java.io.IOException;
public class IO_09_FileInputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("a.txt");
/*
//方法一:
int i = 0;
while((i = fis.read())!=-1){
System.out.println((char)i);
}*/
/*//方法二:available方法返回文件的字节数,可以创建字节数组一次接收,文件较大时慎用.
byte[] b = new byte[fis.available()];
fis.read(b);
System.out.println(new String(b));*/
//方法三:建议使用
byte[] b = new byte[1024];
int len = 0;
while((len=fis.read(b))!=-1){
System.out.println(new String(b,0,len));
}
}
}
BufferedOutputStream
BufferedOutputStream的方法:略,类似于BufferedWriter.只是操作的是字节数组
BufferedInputStream
BufferedInputStream的方法:略.类似于BufferedReader.只是操作的是字节数组
IO_10_FileOutputStream_FileInputStream_Practice.java
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class IO_10_FileOutputStream_FileInputStream_Practice {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("1.jpg");
FileOutputStream fos = new FileOutputStream("2.jpg");
byte[] b = new byte[1024];
int len = 0;
while((len=fis.read(b))!=-1){
fos.write(b,0,len);
}
/*//一个一个读取,不要使用这种低效率的方式
int ch = 0;
while((ch=fis.read())!=-1){
fos.write(ch);
}*/
fis.close();
fos.close();
}
}
IO_11_BufferedOutputStream_BufferedInputStream_Practice.java
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class IO_11_BufferedOutputStream_BufferedInputStream_Practice {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("1.jpg");
FileOutputStream fos = new FileOutputStream("3.jpg");
BufferedInputStream bufis = new BufferedInputStream(fis);
BufferedOutputStream bufos = new BufferedOutputStream(fos);
byte[] b = new byte[1024];
int len = 0;
while((len=bufis.read(b))!=-1){
bufos.write(b,0,len);
//使用缓冲区write时记得刷新哦~
bufos.flush();
}
bufis.close();
bufos.close();
}
}
练习键盘输入:输入一个小写字母组成的字符串,换行后显示大写形式,如果输入over停止读入
使用这种方式虽然可以将InputStream读取的字节流转换成字符串但是太麻烦,可以使用之后介绍的InputStreamReader直接转换为字符流.键盘录入通常使用InputStreamReader
IO_13_readfromKeyboard.java
import java.io.IOException;
import java.io.InputStream;
public class IO_13_readfromKeyboard {
public static void main(String[] args) throws IOException {
InputStream in = System.in;
StringBuffer sb = new StringBuffer();
int t = 0;
while ((t = in.read()) != -1) {
if ((char) t == '\r') {
continue;
}
if ((char) t == '\n') {
String temp = sb.toString();
System.out.println(temp.toUpperCase());
sb.delete(0, sb.length());
if (temp.equals("over")) {
break;
}
} else {
sb.append((char) t);
}
}
}
}
字节流转换为字符流的桥梁-----InputStreamReader的作用:从键盘读取时将其转为字符流,以便使用字符流缓冲区操作
IO_14_InputStreamReader.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class IO_14_InputStreamReader {
public static void main(String[] args) throws IOException {
//字节流转换为字符流,使用InputStreamReader
//获取键盘录入,记住下面这句话!
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line=null;
while(!"over".equals(line=bufr.readLine())){
System.out.println(line);
}
}
}
IO_15_OutputStreamWriter.java
字符流转换为字节流------作用:使用BufferedWriter输出到控制台上
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class IO_15_OutputStreamWriter {
public static void main(String[] args) throws IOException {
// 向控制台输出.字符流变字节流,用OutputStreamWriter,<span style="font-family: Arial, Helvetica, sans-serif;">记住下面这句话!</span>
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
bufw.write("aaaa哈哈\r\nbbb".toCharArray());
bufw.newLine();
bufw.flush();
}
}
IO_16_InputStramReader_OutputStreamWriter_Practice.java
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class IO_16_InputStramReader_OutputStreamWriter_Practice {
public static void main(String[] args) throws IOException {
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line=null;
while(!"over".equals(line=bufr.readLine())){
bufw.write(line.toCharArray());
bufw.newLine();
bufw.flush();
}
bufr.close();
bufw.close();
}
}
小总结:
读取字节流--InputStream--加缓冲区--BufferedInputStream
读取字符流--Reader--加缓冲区--BufferedReader
写入字节流--OutputStream--加缓冲区--BufferedOutputStream
写入字符流--Writer--加缓冲区--BufferedWriter
从键盘读:
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
写入控制台:
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
练习:选择合适的流对象
练习1:将a.txt复制到b.txt中
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
练习2:将a.txt打印到控制台上
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
练习3:将键盘输入的数据写入a.txt中
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new FileWriter("a.txt"));
练习4:将键盘输入的数据打印到控制台上
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
练习5:将a.txt中的数据按照指定编码表uft-8写入到b.txt中--使用转换流的方法.
IO_17_TransStream_Charset.java
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class IO_17_TransStream_Charset {
public static void main(String[] args) throws IOException {
//5.将a.txt中的数据按照指定编码表uft-8写入到b.txt中
//FileReader,FileWriter使用的是系统默认的编码表(简体中文则为GBK),不能使用此类
//转换流有指定编码表的方法,转换流的参数是字节流对象,则为FileOutputStream,FileInputStream
FileInputStream fis = new FileInputStream("a.txt");
FileOutputStream fos = new FileOutputStream("b.txt");
BufferedReader bufr = new BufferedReader(new InputStreamReader(fis,"utf-8"));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(fos,"utf-8"));
String line = null;
while((line=bufr.readLine())!=null){
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufr.close();
bufw.close();
}
}
上面的对象只能操作数据,如何操作文件呢?使用File对象
1.File构造函数和静态属性.
IO_18_File_Separator.java
import java.io.File;
public class IO_18_File_Separator {
public static void main(String[] args) {
//构造函数1:建立一个名为a.txt的File对象,该File对象可以表示一个文件或文件夹
File f1 = new File("a.txt");
//构造函数2:建立一个名为c:\\a.txt的<span style="font-family: Arial, Helvetica, sans-serif;">File</span><span style="font-family: Arial, Helvetica, sans-serif;">对象</span>
File f2 = new File("c:\\");
File f3 = new File(f2, "b.txt");
//构造函数:建立一个名为c:\\a.txt 的File对象
File f4 = new File("c:"+File.separator, "c.txt");
System.out.println(f2);
System.out.println(f3);
System.out.println(f4);
//文件分隔符(Unix中是/,Windows中是\),路径分隔符(Unix中是:,Windows中是;)
System.out.println(File.separator+File.pathSeparator);
}
}
2.File对象的方法之获取
import java.io.File;
import java.text.DateFormat;
import java.util.Date;
public class IO_19_File_Methods {
public static void main(String[] args) {
File f = new File("a.txt");
//获取名称
System.out.println(f.getName());
//获取绝对路径
System.out.println(f.getAbsolutePath());
//获取相对路径,即当前文件夹
System.out.println(f.getPath());
//获取所占总空间,虚拟机可用空间,可用空间
System.out.println(f.getTotalSpace()+","+f.getUsableSpace()+","+f.getFreeSpace());
//获取长度
System.out.println(f.length());
//获取上次修改时间
Date date = new Date(f.lastModified());
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);
System.out.println(df.format(date));
}
}
3.File对象的方法之创建和删除
IO_20_File_Methods2.java
import java.io.File;
import java.io.IOException;
public class IO_20_File_Methods2 {
public static void main(String[] args) throws IOException {
//1.文件的创建和删除
File f = new File("a.txt");
//createNewFile()创建一个文件,成功返回true,已存在返回false
System.out.println(f.createNewFile());
//detele()删除文件
System.out.println(f.delete());
//2.一个目录(文件夹)的创建和删除
File dir = new File("aaa");
//mkdir()创建目录(文件夹),成功返回true,已存在返回false
System.out.println(dir.mkdir());
//delete()删除一个空目录(文件夹),不走回收站,如果文件夹不为空,则无法删除.
System.out.println(dir.delete());
//2.多级目录的创建和删除
//mkdirs()创建多级目录
File dir2 = new File("aa/bb/cc/dd/de");
//创建多级目录
System.out.println(dir2.mkdirs());
//删除目录的最后一个文件夹
System.out.println(dir2.delete());
}
}
4.File对象的方法之判断,重命名,ListRoots,
IO_21_File_Methods3.java
import java.io.File;
public class IO_21_File_Methods3 {
public static void main(String[] args) {
//文件File方法之判断
File f = new File("a.txt");
f.mkdir();
//f.createNewFile();
//判断文件是否存在,最后先判断是否存在,再判断文件类型是文件还是目录
System.out.println(f.exists());
//判断是否是文件
System.out.println(f.isFile());
//判断是否是目录
System.out.println(f.isDirectory());
//重命名
File f1 = new File("b.txt");
//在同一个文件夹中则重命名,将b.txt命名为bbb.txt
System.out.println(f1.renameTo(new File("bbb.txt")));
//在不同文件夹中则剪切,将b.txt剪切到d:\\bbb.txt
System.out.println(f1.renameTo(new File("d:\\bbb.txt")));
//listRoots列出可用系统根目录,静态方法
File[] listRoots = File.listRoots();
for (File file : listRoots) {
System.out.println(file);
}
//list列出该目录下所有文件和文件夹的名称,包括隐藏文件.若访问系统级目录会出异常.目录为空则创建的数组长度为0.
File f2 = new File("c:\\");//必须是目录,不能是文件
String[] names = f2.list();
for (String name : names) {
System.out.println(name);
}
}
}
list方法练习:过滤器
输出d盘下所有扩展名为.txt的文件
IO_22_File_Method_list.java
import java.io.File;
import java.io.FilenameFilter;
public class IO_22_File_Method_list implements FilenameFilter{
private String suffix;//后缀
public IO_22_File_Method_list(String suffix) {
super();
this.suffix = suffix;
}
public static void main(String[] args) {
File f = new File("d:\\");
//list(FilenameFileter filter)创建接口,实现accept方法,方法中写过滤条件.
String[] names = f.list(new IO_22_File_Method_list(".txt"));
for (String name : names) {
System.out.println(name);
}
}
@Override
//对文件路径和文件名进行过滤
public boolean accept(File dir, String name) {
return name.endsWith(suffix);
}
}
过滤隐藏文件:使用FileFilter接口
IO_23_File_Method_list2.java
import java.io.File;
import java.io.FileFilter;
public class IO_23_File_Method_list2 implements FileFilter{
public static void main(String[] args) {
File f = new File("c:\\");
File[] files = f.listFiles(new IO_23_File_Method_list2());
for (File file : files) {
System.out.println(file);
}
}
@Override
public boolean accept(File name) {
return !name.isHidden();
}
}
Properties对象
IO_24_Properties.java
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
import java.util.Set;
public class IO_24_Properties {
public static void main(String[] args) throws IOException {
/*
Map
|--HashTable
|--Properties
Properties集合:用于操作以键值对形式存在的配置文件.
特点:1.该集合中的键和值都是字符类型的
2.集合中数据可以保存在流中,从流读取
*/
Properties p = new Properties();
//存储元素
p.setProperty("jhz", "19920811");
p.setProperty("ztq", "19920221");
p.setProperty("ddd", "19920421");
//修改元素
p.setProperty("ddd", "19990101");
//遍历元素->使用stringPropertyNames方法返回key的set集合.
Set<String> propertyNames = p.stringPropertyNames();
for (String name : propertyNames) {
System.out.println(name+p.getProperty(name));
}
//list方法,一般用于调试
// p = System.getProperties();
p.list(System.out);//将p放入输出流中
//从输出流持久化数据到文件中,第一个参数的是使用的输出流,第二个参数是描述,默认使用ISO-8859-1,描述信息不要写中文
OutputStream os = new FileOutputStream("info.txt");
p.store(os, "name,birthday");
}
}
IO_25_Properties2.java
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
/**
* 读取配置文件中jhz的登录次数,并+1后重新保存进配置文件.
* @author Administrator
*
*/
public class IO_25_Properties2 {
public static void main(String[] args) throws IOException {
Properties p = new Properties();
FileInputStream fis = new FileInputStream("info.txt");
//从输出流中读取属性列表ISO8859-1
p.load(fis);
//读取并将登录次数加1
String property = p.getProperty("jhz");
int value = Integer.parseInt(property)+1;
p.setProperty("jhz",value+"");
FileOutputStream fos = new FileOutputStream("info.txt");
p.store(fos, "name,Logintimes");
fis.close();
fos.close();
}
}
PrintStream打印流:可以直接操作输入流和文件
提供了多种不同数据的print方法,并可以保持数据的原有形式,不抛异常.
当想保持数据原样写入时使用PrintStream最方便
构造函数
PrintStream(String s);
PrintStream(File f);
PrintStream(OutputStream os);
write(int i):此方法向输出流写入一个字节,要写入的是i的八个低位,24个高位将被忽略. 所以i=97和i=609输出的都是a.
print(各种参数):原样打印
IO_26_PrintStream.java
import java.io.IOException;
import java.io.PrintStream;
public class IO_26_PrintStream {
public static void main(String[] args) throws IOException {
PrintStream ps = new PrintStream("a.txt");
ps.write(609);
ps.write(97);
ps.print(97);
ps.print("aaa");
ps.print(1.256);
ps.close();
//打印结果aa97aaa1.256
}
}
PrintWriter:打印流
构造函数:
PrintWriter(String s):
PrintWriter(File f):
PrintWriter(OutputStream os):
PrintWriter(Writer w):
IO_27_PrintWriter.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class IO_27_PrintWriter {
public static void main(String[] args) throws IOException {
//为true则自动刷新,不用调用flush
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(System.out,true);
String line=null;
while(!"over".equals(line=bufr.readLine())){
pw.println(line);
}
pw.close();
}
}
SequenceInputStream:
SequenceInputStream(Enumeration<?>InputStream):
read(byte[] b):
IO_28_SequenceInputStream_Enum.java
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.Enumeration;
import java.util.Vector;
public class IO_28_SequenceInputStream_Enum {
/**
* 将1.txt,2.txt,3.txt中的数据写入4.txt中
* Vector的elements方法可以得到枚举.
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
Vector<FileInputStream> inputStreams = new Vector<FileInputStream>();
inputStreams.add(new FileInputStream("1.txt"));
inputStreams.add(new FileInputStream("2.txt"));
inputStreams.add(new FileInputStream("3.txt"));
Enumeration<FileInputStream> en = inputStreams.elements();
//SequenceInputStream参数是枚举类型,通过vector.elements获得.
SequenceInputStream sis = new SequenceInputStream(en);
BufferedOutputStream bufw = new BufferedOutputStream(new FileOutputStream("4.txt"));
byte[] b = new byte[1024];
int len = 0;
while((len=sis.read(b))!=-1){
bufw.write(b, 0, len);
bufw.flush();
}
sis.close();
bufw.close();
}
}
IO_29_SequenceInputStream_Enum2.java
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
public class IO_29_SequenceInputStream_Enum2 {
public static void main(String[] args) throws IOException {
/**
* Vector效率较低,可以使用ArrayList,使用Collections的Enumeration方法获得该集合(ArrayList)的枚举
*/
ArrayList<InputStream> al = new ArrayList<InputStream>();
al.add(new FileInputStream("1.txt"));
al.add(new FileInputStream("2.txt"));
al.add(new FileInputStream("3.txt"));
Enumeration<InputStream> en = Collections.enumeration(al);
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("4.txt");
int len = 0;
byte[] b = new byte[1024];
while((len = sis.read(b))!=-1){
fos.write(b,0,len);
}
sis.close();
fos.close();
}
}
应用:文件切割器.输入流一个,输出流在每次循环时指定切割成的文件名即可.
IO_30_FileCutter.java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class IO_30_FileCutter {
public static void main(String[] args) throws IOException {
//参数为切割的的文件路径
fileCutter(new File("1.txt"));
}
private static void fileCutter(File file) throws IOException {
//切割的文件file
FileInputStream fis = new FileInputStream(file);
//按1M为单位切割.
byte[] b = new byte[1024];
//保存在哪个文件夹下,不存在该文件夹则创建
File dir = new File("c:\\Filecutter");
if(!dir.exists()){
dir.mkdir();
}
int len=0;
//计数器,用于按顺序记录切割的每一份,便于之后合并.
int count = 1;
FileOutputStream fos = null;
while((len=fis.read(b))!=-1){
//使用new File(File parent,String child)构造指定切割到的文件夹,保存在C:\Filecutter下;
fos = new FileOutputStream(new File(dir,(count++)+".part"));
fos.write(b,0,len);
}
//建立配置文件,以保存切割信息(原文件名,切割份数等),保存在C:\Filecutter下
Properties p = new Properties();
fos = new FileOutputStream(new File(dir,(count)+".properties"));
p.setProperty("fileName", file.getName());
p.setProperty("fileParts", count-1+"");
p.store(fos, "file properties info");
//关闭流
fis.close();
fos.close();
}
}
文件合并--使用SequenceInputStream
IO_31_File_Merge.java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Properties;
public class IO_31_File_Merge implements FilenameFilter{
private static String suffix;
public IO_31_File_Merge(String suffix) {
super();
this.suffix = suffix;
}
public static void main(String[] args) throws IOException {
FileMerge(new File("c:\\Filecutter"));
}
private static void FileMerge(File file) throws IOException {
String[] list = file.list(new IO_31_File_Merge(".properties"));
String property = list[0];
FileInputStream fis = new FileInputStream(file+"\\"+property);
Properties p = new Properties();
p.load(fis);
String fileName = p.getProperty("fileName");
int fileParts = Integer.parseInt(p.getProperty("fileParts"));
ArrayList<InputStream> al = new ArrayList<InputStream>();
for (int i = 1; i <= fileParts; i++) {
al.add(new FileInputStream(new File(file,i+".part")));
}
Enumeration<InputStream> en = Collections.enumeration(al);
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream(new File(file,fileName));
byte[] b = new byte[1024];
int len = 0;
while((len=sis.read(b))!=-1){
fos.write(b,0,len);
}
sis.close();
fos.close();
}
@Override
public boolean accept(File dir, String name) {
return name.endsWith(suffix);
}
}
对象的序列化 ObjectOutputStream.writeObject()
对象的反序列化 ObjectInputStream.readObject()
序列化是流功能的拓展,所以接收一个InputStream和OutputStream对象.正如缓冲流和转换流,也需要接收对象,都是其他流结合使用的.
IO_32_serializable.java
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class IO_32_serializable{
public static void main(String[] args) throws IOException, ClassNotFoundException{
serialize(new IO_33_bean(1,"lj","haha"));
oppoSerialize("obj.object");
}
private static void oppoSerialize(String file) throws IOException, ClassNotFoundException {
//对象的反序列化.读取使用ObjectOutputStream已经保存在硬盘上的对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
IO_33_bean person = (IO_33_bean) ois.readObject();
System.out.println(person.getId());//1
System.out.println(person.getName());//lj
System.out.println(person.getPassword());//null
ois.close();
}
private static void serialize(IO_33_bean person) throws IOException {
//对象的序列化:将对象存储到硬盘上延长它的生命周期.该对象必须先实现Serializable接口
//使用ObjectOutputStream类的writeObject方法存储. 存储文件的扩展名为.object
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.object"));
oos.writeObject(person);
oos.close();
}
}
需要序列化的对象对应的类---数据库对象和具有特殊数据的对象可以使用序列化保存.并不是所有对象都可以被序列化,如Socket对象就不行
IO_33_bean.java
import java.io.Serializable;
public class IO_33_bean implements Serializable{
/**
* 序列化强烈建议加入UID,以判断.object文件与类文件是不是同一个.只要id一样,就可以反序列化,
* 否则可能出现InvalidClassException异常,该id的访问修饰符ACCESS MODIFIER可以为任意.
* 静态属性不在堆中,不能进行序列化.不想被序列化的属性可以用transient标识为瞬态的,则不被存储.
*/
private static final long serialVersionUID = 1L;
private int id;
private String name;
private transient String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
public IO_33_bean(int id, String name, String password) {
super();
this.id = id;
this.name = name;
this.password = password;
}
}
随机访问文件对象RandomAccessFile
IO_34_RandomAccessFile.java
import java.io.IOException;
import java.io.RandomAccessFile;
public class IO_34_RandomAccessFile {
/*RandomAccessFile
* 1.不是既能读,又能写.其实内部封装了字节输入输出流.
* 2.内部维护了一个byte数组,并用一个指针,通过seek方法设置指针位置.通过getFilePointer方法获取指针位置.
* 3.与流对象存取不同,它可以从任意位置存取,多线程方式有些操作就是用的该类,应用比如视频断点续传.
*/
public static void main(String[] args) throws IOException {
readFile();
writeFile();
}
private static void writeFile() throws IOException {
RandomAccessFile raf = new RandomAccessFile("random.txt", "rw");
raf.write("张三".getBytes());//2个中文占4个字节
raf.writeInt(99);//使用4个字节存储int对象
System.out.println(raf.getFilePointer());//8
raf.seek(2*8);//从第16个字节开始写
raf.write("李刚".getBytes());
raf.writeInt(100);
//记事本解析为:张三 c 李刚 d
//数据c和d没错,因为记事本用GBK解析了
raf.close();
}
private static void readFile() throws IOException {
RandomAccessFile raf = new RandomAccessFile("random.txt", "rw");
byte[] b = new byte[8];
raf.read(b);
System.out.println(new String(b));//张三 c
System.out.println(raf.getFilePointer());//8
raf.seek(16);
raf.read(b);
System.out.println(new String(b));//李刚 d
}
}
管道流--常用于多线程--输出的内容只能有自己获取
IO_35_PipedInputStream_PipedOutputStream.java
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class IO_35_PipedInputStream_PipedOutputStream {
/**
* 管道流,输出流写的数据只能输入流读.需要连接输入流和输出流.使用PipedInputStream的connect方法
* 一般使用多线程执行,否则可能造成死锁.
*/
public static void main(String[] args) throws IOException {
PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream();
pis.connect(pos);
Input input = new Input(pis);
Output output = new Output(pos);
Thread t1 = new Thread(input);
Thread t2 = new Thread(output);
t1.start();
t2.start();
}
}
class Input implements Runnable{
private PipedInputStream pis;
public Input(PipedInputStream pis) {
this.pis = pis;
}
@Override
public void run() {
byte[] b = new byte[1024];
try {
int len = pis.read(b);
System.out.println(new String(b,0,len));//泥濠啊大哥
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Output implements Runnable{
private PipedOutputStream pos;
public Output(PipedOutputStream pos) {
this.pos = pos;
}
@Override
public void run() {
try {
pos.write("泥濠啊大哥".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
DataInputStream,DataOutputStream操作基本数据类型,构造函数接收流字节参数
在存取基本数据类型时使用.
IO_36_DataInputStream_DateOutputStream.java
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class IO_36_DataInputStream_DateOutputStream {
public static void main(String[] args) throws IOException {
read();
write();
}
private static void write() throws IOException {
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeUTF("66666哈哈");
dos.writeInt(999);
}
private static void read() throws IOException {
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
byte[] b = new byte[1024];
int len = dis.read(b);
System.out.println(new String(b,0,len));//wirteUTF存储的只有readUTF可以取出来
dis.close();
}
}
操作数组的流:源或者目的是[内存]时使用该流.
操作字节数组ByteArrayInputStream,ByteArrayOutputStream
操作字符数组ChaArrayReader,CharArrayWriter,
操作字符串数组StringReader,StringWriter
IO_37_ByteArrayInputStream_ByteArrayOutputStream.java
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
public class IO_37_ByteArrayInputStream_ByteArrayOutputStream {
public static void main(String[] args) {
ByteArrayInputStream bis = new ByteArrayInputStream("哈哈".getBytes());
//ByteOutputStream内部维护了一个数组,缓冲区随输入的写入自动增长,使用toString方法可以将缓冲区里的内容转换为字符串.
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int i = 0;
while((i=bis.read())!=-1){
bos.write(i);
}
System.out.println(bos.toString());//哈哈
}
}