您的位置:首页 > 职场人生

黑马程序员_IO流(下)

2012-09-18 00:43 232 查看
---------- android培训java培训、期待与您交流!
----------

1.标准输入流:in

它是JVM从底层去找系统默认的输入设备,其read方法属于阻塞式方法,有数据则读,没数据则等待输入数据。
InputStream in = System.in;//从键盘输入一个字节流对象,如a
int ch1=in.read();
System.out.println("ch1="+ch1);//97  'a'
int ch2=in.read();
System.out.println("ch2="+ch2);//13 '\r'
int ch3=in.read();
System.out.println("ch3="+ch3);//10  '\n'


注意:键盘录入要明确结束标记,否则不能结束程序。

例:将键盘录入的内容写入到文件中,且将全部字母转为大写;
//从键盘输入流对象
BufferedReader br=new BufferedInputStream(new InputStreamReader(new FileInputStream(System.in)));
//目的地
BufferedWriter bw=new BufferedOutputStream(new OutputStreamWriter(new FileOutputStream("c:\\Demo.java")));
String line=null;
while((line=br.readLine)!=null){
//判断结束标记
if("over".equals(line)
break;
bw.write(line.toUpperCase);
bw.newLine();
bw.flush();
}
br.close();
bw.close();


2.标准输出流:System.out

例:将键盘录入的内容显示在显示器上
//从键盘输入流对象
BufferedReader br=new BufferedInputStream(new InputStreamReader(new FileInputStream(System.in)));
//目的地
BufferedWriter bw=new BufferedOutputStream(new OutputStreamWriter(new FileOutputStream(System.out)));
String line=null;
while((line=br.readLine)!=null){
//判断结束标记
if("over".equals(line)
break;
bw.write(line.toUpperCase);
bw.newLine();
bw.flush();
}
br.close();
bw.close();


3.流操作规律总结:那是因为流可以处理数据,但是处理数据的流对象很多,都有各自的特点和功能,处理数据时,到底使用的是哪个流对象?流的操作无非就是读和写,所以通过几个明确就可以具体确定使用哪个对象。

1.确定源还是目的

源:InputStream Reader

目的:OutputStream Writer

确定读还是写

2.确定的是处理的数据是否是纯文本的数据?

是纯文本,源:Reader
目的:Writer

不是纯文本,直接用字节流,确定了具体的体系。

3.找体系中的具体对象,确定的是数据所在的具体设备。

源:硬盘:前缀名是File的流对象

键盘:System.in

内存:数组

网络:Socket

目的:硬盘:前缀名是File的流对象

显示器:System.out

内存:数组

网络:Socket

就可明确具体的流对象了。

4.明确具体对象后,一定要继续明确是否需要额外功能

1.高效:Buffered

2.转换编码:InputStreamReader OutputStreamWriter 桥梁

4.将四个明确应用到具体需求中

需求1:将一个字符串写入到一个文件中;

明确一:是目的;

明确二:是纯文本数据,这就已经明确了具体的体系Writer

明确三:具体设备是硬盘,前缀名File,后缀名Writer,所以FileWriter

FileWriter fw=new FileWriter("1.txt");

明确四:需要高效额外功能 Buffered

BufferedWriter bw=new BufferedWriter(new FileWrier("1.txt"));

需求2:复制一个文本文件(有可能会操作其中的字符或者字符串)

明确一:源和目的,源Reader,InputStream 目的Writer,OutputStream

明确二:是纯文本数据,Reader Writer

明确三:具体设备,源和目的的具体设备都是硬盘,FileReader和FileWriter

FileReader fr=new FileReader("a.txt");

FilWriter fw=new FileWriter("b.txt");

//剩下的就是读写操作

明确四:需要高效额外功能

BufferedReader br=new BufferedReader(new FileReader("1.txt"));

BufferedWriter br=new BufferedWriter(new FileWrtier("2.txt"));

//剩下读写操作

需求3:读取键盘录入数据,写入到一个文件中

明确一:源和目的,源Reader,InputStream 目的Writer,OutputStream

明确二:是纯文本数据,Reader Writer

明确三:源:键盘,System.in

目的:硬盘,FileWriter

InpuStream in=System.in;

//若源为字节流对象,则可以使用字节流的读read方法读到字节,再将这个字节存储到字节数组中

//将其转为字符串,再用字符流的存储。

FileWriter fw=new FileWriter("a.txt");

明确四:需要转换的额外功能,要将字节数据转换为字符数据,这样操作起来很便捷。

InputStreamReader isr=new InputStreamReader(System.in);

FileWriter fw=new FileWriter("a.txt");

还需要额外功能:高效

BufferedReader br=new BufferedInputStream(new InputStreamReader(FileInSystem.in));

需求4:读取一个已有的默认编码的文本文件,想要将这些数据按照指定的编码UTF-8写到另一个文件中‘

明确一:源和目的,源Reader,InputStream 目的Writer,OutputStream

明确二:是纯文本数据,Reader Writer

明确三:具体设备

源:硬盘FileReader

目的:硬盘FileWriter

注意:源对象可以使FileReader,因为FileReader中内置的默认的就是本地编码;但目的是指定编码,所以不可以用FileWriter,需要额外功能。

明确四:需要转换流转换编码

字符到字节OutputStreamWriter,该转换流必须要接受一个字节流,而且还要对应的设备是硬盘,所以该对象是FileOutputStream.

5.File类:用来将文件或者文件夹封装成对象;

作用:方便对文件与文件夹的属性信息进行操作;提供了很多的方法对其进行操作。

构造函数:File f1=new File("d:\\abc.txt");//将d:\中的abc.txt封装成了file对象,既可以封装已存在文件,也可以封装不存在的文件或文件夹。

File f2=new File("d:\\","abc.txt");//具体操作D盘下的文件可以写成d:\\,x.

//f2中,D盘是一个字符串对象

File dir=new File("d:\\");//d盘是一个file对象

File f2=new File(dir,"abc.txt");

File字段:field

获取文件分隔符:System.getProperty("file.separator");在File类中,静态的separator方法内部调用了获取文件分隔符的方法。

File f=new File("d:"+File.separator+"a.txt");

获取路径分隔符:pathSeparator()静态的;

方法:

文件的创建和删除:

File f1=new File("d:\\abc.txt");

boolean b=f1.createNewFile();//要抛异常

//删除文件,java删除不走回收站。

boolean b2=f1.delete();

注意:如果该文件不存在,则创建;如果存在,则不创建;对于输出流,无论文件是否存在,都创建,存在就覆盖。除非传入一个boolean参数,
进行续写,则不覆盖。

文件夹的创建和删除:

File dir=new File("d:\\hehe");

//创建目录

boolean b1=dir.mkdir();//mkdirs创建多级目录,若hehe\\qq\\zzz,用mkdirs.

//删除目录

boolean b2=dir.delete();//删除了最里面的一个目录

注意:文件夹删除必须先删除内部的内容,保证文件夹为空才可以为空,否则删不掉。

判断:

在判断是否是文件的时候,首先要判断文件是否存在;必须先存在,才能判断文件目录。

exists():判断文件是否存在;

isFile():判断是否是文件;

isDir():判断是否是目录;

获取:

File f=new File("d:\\myclass\\CopyDemo3.java");

f.getName();//获取文件名

f.getAbsolutePath();//获取绝对路径

f.getPath();//获取路径;File对象中封装的是什么,获取到的路径就是什么。

f.getParent();//获取父目录;即前一个文件分隔。

long time=f.lastModify();//返回最后修改时间;得到的是毫秒值,将毫秒值转为日期对象,再转为字符串;

f.length();//获取文件大小;

f.getFreeSpace();//获取未分配的空间;

f.getUserableSpace();//获取可用空间;

//静态方法,显示所有有效盘符

File[] roots=File.listRoots();

for(File f:roots){

System.out.println(f);

}

//修改名字

File f1=new File("d:\\myclass\\0.bmp");

File f2=new File("d:\\1.bmp");

f2.renameTo(f1);

6.Filter:过滤器

过滤原理:首先将所有文件全列出来,遍历其中加的条件,用到方法accept;

7.递归:函数自身调用自身;

什么时候用:当一个功能被重复使用,但是每次调用时,传入的参数都和上次的运算结果有关,这时可以选择递归完成;

前提:1.必须要定义条件,否则会死;

2.必须要控制递归次数,否则栈内存溢出。

练习:列出一个目录中所有的内容,包含子目录。

import java.io.File;
import java.io.IOException;
public class Test{
public static void main(String[] args) throws IOException {
File dir=new File("d:\\my");
listAll(dir,0);
}
private static void listAll(File dir,int level) {
System.out.println(getSpace(level)+dir);
level++;
File[] files=dir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
listAll(file, level);
}
System.out.println(getSpace(level)+file);
}

}
private static String getSpace(int level) {
StringBuilder sb=new StringBuilder();
for (int i = 0; i < level; i++) {
sb.append("|--");
}
return sb.toString();
}
}


练习:删除一个带内容的目录。
public static void main(String[] args) throws IOException {
File dir=new File("d:\\my");
removeAll(dir);//删除文件夹
}
private static void removeAll(File dir) {
File[] file=dir.listFiles();
for (File files : file) {
if (files.isDirectory()) {
removeAll(files);
}
else
files.delete();
}
dir.delete();
}


练习:将指定目录下的所有的java文件的绝对路径存储到一个文本文件中。包含子目录中的java文件。
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.filechooser.FileFilter;
public class Test {
public static void main(String[] args) throws IOException {
File dir=new File("e:\\java");
FileFilter f=new FileFilter(){
@Override
public boolean accept(File f) {
return f.getName().endsWith(".java");
}
@Override
public String getDescription() {
return null;
}
};
List<File> list=new ArrayList<File>();
getList(dir,f,list);
File dest=new File(dir,"demo.java");
writeList(list,dest);
}

//对指定目录进行递归,将符合filter过滤条件的file对象存储到指定集合中。
public static void getList(File dir, FileFilter f, List<File> list) {
File[] file=dir.listFiles();
for (File file2 : file) {
if (file2.isDirectory()) {
getList(file2, f, list);
}
else
if (f.accept(file2)) {
list.add(file2);
}
}
}
//将集合中的file对象的信息写入到目标文件中。
public static void writeList(List<File> list,File f){
//创建流对象
BufferedWriter bw=null;
try {
bw=new BufferedWriter(new FileWriter(f));
//迭代集合
for (File file : list) {
bw.write(file.getAbsolutePath());
bw.newLine();
bw.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
finally{
if(bw!=null){
try {
bw.close();
} catch (IOException e) {

e.printStackTrace();
}
}
}

}

}


8.Properties类:

Map的子类,存入的键和值都是字符串,属性集,是和IO技术相结合的Map集合,可将集合中的数据存储到持久化的设备上;

基本应用:存储和读取;

演示:
Properties pro=new Properties();//创建
pro.setProperty("zs",32);//存数据
String value=pro.getProperty("zs");//获取一个
System.out.println(value);

//获取多个
pro.setProperty("zs",32);
pro.setProperty("ls",13);
pro.setProperty("yg",24);
pro.list(System.out);//获取所有数据显示在显示器上

注意:list方法对调试有用,和IO技术相结合。

该集合可将数据存储到持久化的设备上们也可以将持久化设备上的规范数据存储带集合中,这里的规范是指成键值对且都是字符串;
Properties pro=new Properties();
FileInputStream fis=new FileInputStream("d:\\my\\java.txt");
pro.load(fis);//将流操作的数据存储到集合中
pro.setProperty("liso","12");//修改数据,键和值都是字符串

FileOutputStream fos=new FileOutputStream("d:\\my\\java.txt");
pro.store(fos,"");//修改后将其同步至文件中,此方法需要注释的参数
fos.close();
fis.close();


练习:记录程序运行次数,如果达到5次,就显示"使用次数已到,请注册!"。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

public class e {
public static void main(String[] args) throws IOException{
if (checkCount()) {
System.out.println("程序运行");
}

}

private static boolean checkCount() throws IOException {
//定义一个集合存储计数器
Properties pro=new Properties();
//定义一个配置文件
File config=new File("d:\\config.properties");
if (!config.exists()) {
config.createNewFile();
}
//定义一个输入流将配置文件和数据相关联;
FileInputStream fis=new FileInputStream(config);
//将流关联的数据加载进集合
pro.load(fis);
int count=0;
String value=pro.getProperty("count");
if (value!=null) {
count=Integer.parseInt(value);
if (count>=5) {
System.out.println("使用次数已到,请注册!");
return false;
}
}
count++;
pro.setProperty("count",Integer.toString(count));
//再将次数记录到配置文件中
FileOutputStream fos=new FileOutputStream("d:\\config.properties");
//存储集合中的元素到配置文件中
pro.store(fos,"");
fis.close();
fos.close();

return true;
}

}


IO流中的的其它功能类

1.打印流:PrintSream PrintWriter

作用:可以直接操作输入流文件;

printStream:

注意:PrintStream永远不抛IO异常,使用默认字符编码转换为字节;

打印目的:1.File对象
2.字符串路径
3.字节流输出流

演示:

PrintStream ps = new PrintStream("d:\\demo.java");
ps.write(97);//写入结果是a,一次写一个字节
ps.print(97);//写入结果是97,结果是两个字节,发现数据值表现形式没变,但二进制数值变了。

write和print方法的区别:

write:将一个整数的二进制数的四位中最低位字节写入目的地;

print:将一个整数的表现形式写入目的地,目的的数据和打印时的数据表现形式相同,其实是将整数转成字符串通过

String.valueOf(int i),保证了数据的表现形式,然后将这个字符串中的字节写入。

print的应用场景:如果想要保证数据值的表现形式时,就可以使用打印流的打印方法。

PrintWriter:

能接收输入流,自动刷新 boolean autoFlush;

演示:
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
printWriter pw=new PrintWriter(System.out,true);//构造函数中加上true,带上自动刷新。
String line=null;

while((line=br.readLine()!=null){
if("over".equals(line)){
break;
}
pw.println(line.toUpperCase());
pw.flush();//不带自动刷新就手动刷新
}
pw.close();
br.close();

注意:对于系统的标准输入和输出,如果需要在以后的程序中继续使用,不要关闭流。

2.序列流:SequenceInputStream

作用:对多个流进行合并;

原理:内部封装了一个集合,也是在操作一个有序集合中的多个对象,即将多个流合并为一个流。

演示:出现于jdk1.0版本,只有Vector集合;
FileInputStream fis1 = new FileInputStream("d:\\demo1.java");
FileInputStream fis2 = new FileInputStream("d:\\demo2.java");
FileInputStream fis3 = new FileInputStream("d:\\demo3.java");

Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(fis1);
v.add(fis2);
v.add(fis3);

Enumeration<FileInputStream> en = v.elements();
FileOutputStream fos=new FileOutputStream("d:\\demo.java");
byte[] by=new byte[1024];
int len=0;
while((len=fis.read(buf)!=-1){
fos.write(buf,0,len);
}
fos.close();
fis.close();

但Vector效率低,所以使用ArrayList,再通过迭代器,自定义一个枚举对象,仍然很麻烦;可以通过Collections工具类,将Collections集合获取对应的枚举对
象。

Enumeration<FileInputStream> en=Collections.enumeration(al);//这样既高效,又方便。

3.对象的序列化和反序列化:ObjectInputStream ObjectOutputStream,被操作的对象需要实现Serializable这个标记接口。

序列化:将多个对象进行有序排列并持久化存储,可以延长对象的生命周期,防止对象在内存中突然消失。

演示:想要把对象数据写入文件中:

1.目的
2.非纯文本,用字节流OutputStream
3.设备:硬盘 FileOutputStream
4.需要额外功能 :写对象
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("d:\\demo.java");
//自定义一个Person类
oos.writeObject(new Person("lisi",21));//写对象
oos.close();


注意:在这里,如果Person类没有实现Serializable接口,则会出现NotSerializableException。

writeObject():写入的是对象的类、类的签名以及类及其类的超类的非瞬态和非静态字段。

非瞬态字段:即被transient关键字修饰的字段,被修饰后表示生命周期不长,不要被序列化。

反序列化:将多个对象从文件中读出来

ObjectInputStream ois = new ObjectInputStream(new FileIntputStream("d:\\demo.java");
Person p = (Person)ois.readObject();//要抛ClassNotFoundException异常;
System.out.println(p.getName()+"::"+p.getAge());
ois.close();


Serializable:该接口在序列化运行时给每个可序列化的类分配一个SerialVersionUID的版本号,这个ID是由类的各个方面算出来的一个数字,

目的是给需要序列化的类进行ID号的添加,防止反序列化的ID号不匹配,但是使用时必须显示声明UID,方便该类的反序列化。

显示声明的方式:private static final long SerialVersionUID=313l;

注意:静态的数据不可以被序列化,因为被静态了就在静态共享区,不在内存中。

想要将非静态的数据不被序列化,需要transient关键字标识。

4.管道流:PipedOutputStream

作用:将管道输出流与管道输入流相连接来创建通信管道;

特点:1.管道输入流和管道输出流连接;

2.必须结合多线程技术,否则单线程容易出现死锁。

方法:connect将输入输出流连接起来。

5.数据流:DataInputStream DataOutputStream 操作基本数据值;
DataOutputStream dos = new DataOutputStream(new FileOutputStream("d:\\demo.java"));
//保持字节数不变的写入文件中
dos.writeInt(305);//写入的是  &1
dos.close();

DataInputStream dis = new DataInputStream(new FileInputStream("d:\\demo.java"));
int num=dis.readInt();
sop(num);
dis.close();
6.操作字节数组:ByteArrayInputStream ByteArrayOutputStream 是对应设备为内存的对象;

注意:关闭ByteArrayOutputStream无效;因为没有调用底层资源,都在内存中操作,关闭后仍可调用,而不会产生任何IOException;

ByteArrayInputStream内部有一个缓冲区;

演示:
//创建源 内存
ByteArrayInputStream  bis=new ByteArrayInputStream("abds".getBytes());
//创建目的 内存
ByteArrayOutputStream bos=new ByteArrayOutputStream();//内部就有了一个可变长度的缓冲区

int by=0;
while((by=bis.read()!=-1){
bos.write(by);
}
sop(bos.toString());

也可以直接用for循环遍历,但用这个不用管角标,将数组封装成流,用流的思想来操作数组。

7.CharArrayReader和CharArrayWriter,StringReader和StringWriter ,和上面是一样的。

8.RandomAccessFile类:随机访问文件,自身具备读写的方法。

通过getFilePointer(int x),seek(int x)来达到随机访问。

1.该类不是流体系中的对象;

2.用来操作文件的对象;

3.可以进行读写操作的对象;

4.内部定义了一个大型的byte数组,操作文件,而文件又是由字节组成的,用来存储操作的字节数据;

5.有流,而且使用的是字节数组做缓冲,所以是字节流,这个对象其实就是封装了字节流的工具类。

随机访问:就是可以从任意处开始读写;getFilePointer()和seek来获取和设置文件指针,来达到随机访问;

构造函数RandomAccessFile(File,mode)

mode()参数:r:只读,不能写;

rw:读写,如果没有,可以创建;
//写入数据
RandomAccessFile raf=new RandomAccessFile("d:\\demo.java","rw");
//写入人的信息,比如姓名,年龄
raf.write("lisi".getBytes());
raf.writeInt(97);//整数,四个字节

raf.close();

//随机读取数据
RandomAccessFile raf=new RandomAccessFile("d:\\demo.java","r");

raf.seek(8);//改变指针位置,达到随机
byte[] buf=new byte[4];
raf.read(buf);
String name=new String(buf);//将姓名的字节数据转为字符串
int age=raf.readInt();//读取年龄
System.out.println(name+"::"+age);
System.out.println(raf.getFilePointer());//获取文件指针的位置;

raf.close();

//随机写入数据
RandomAccessFile raf=new RandomAccessFile("d:\\demo.java","rw");

raf.seek(8*3);
raf.write("李四".getBytes());//写入字节
raf.writeInt(24);

raf.close();


---------- android培训java培训、期待与您交流!
----------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: