---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
名称 | 对应的对象 |
文件类 | File |
属性类 | Properties |
打印流 | PrintStream、PrintWriter |
管道流 | PipedInputStream |
序列流 | SequenceInputStream |
对象序列化流 | ObjectInputStream、ObjectOutputStream |
随机存取文件类 | RandomAccessFile |
基本数据流 | DataInputStream、DataOutputStream |
字节数组流 | ByteArrayInputStream、ByteArrayOutputStream |
字符数组流 | CharArrayReader、CharArrayWriter |
字符串流 | StringReader、StringWriter |
一、File
该类的出现是对文件系统中的文件及文件夹进行对象的封装。可以通过对象的思想来操作文件以及文件夹,方便对文件及文件夹的属性信息进行操作,File对象可以作为参数传递给流的构造函数。
1、构造函数:
File(String fileName):将一个字符串路径(相对或者绝对)封装成File对象,该路径是可存在的,也可以是不存在的。
File(String parent,String child);
File(File parent,String child);
File f1=new File("a.txt");
File f2=new File("c:\\abc","b.txt");
File d=new File("c:\\abc");
File f3=new File(d,"c.txt");
2、特别的字段:
separator:跨平台的目录分隔符。例如,
File file=new File("c:"+File.separator+"a.txt");
3、常见方法:
1)创建:
boolean createNewFile()throws IOException:创建文件,如果被创建的文件已经存在,则不创建。注意,与输出流创建文件时的情况不同。
boolean mkdir():创建文件夹。
boolean mkdirs():创建多级文件夹。
File f=new File("a.txt");
f.createNewFile();
File d=new File("c:\\abc");
d.mkdir();
2)删除:
boolean delete():可用于删除文件或者文件夹。注意,对于文件夹只能删除不带内容的空文件夹。对于带有内容的文件夹不可以直接删除,必须要从里往外删除。
void deleteOnExit():删除动作交给系统完成。无论是否发生异常,系统在退出时执行删除动作。
File f1=new File("a.txt");
f1.deleteOnExit();
File f2=new File("b.txt");
System.out.println("create:"+f2.createNewFile());//true
System.out.println("delete:"+f2.delete()); //true
3)判断:
boolean canExecute();
boolean canWrite();
boolean canRead();
boolean exists():判断文件或文件夹是否存在。
boolean isFile():判断File对象中封装的是否是文件。
boolean isDirectory():判断File对象中封装的是否是文件夹。
boolean isHidden():判断文件或文件夹是否隐藏。在获取硬盘文件或文件夹时,对于系统目录中的文件,java是无法访问的,所以在遍历时,可以避免遍历隐藏文件。
File f=new File("a.txt");
f.createNewFile();
System.out.println("exists:"+f.exists());//true
System.out.println("isFile:"+f.isFile());//true
System.out.println("isDirectory:"+f.isDirectory());//false
4)获取:
getName():获取文件或文件夹的名称。
getPath():File对象中封装的路径是什么,获取的就是什么。
getAbsolutePath():无论File对象中封装的路径是什么,获取的都是绝对路径。
getParent():获取File对象封装的文件或文件夹的父目录。注意,如果封装的是相对路径,那么返回null。
long length():获取文件大小。
File f=new File("a.txt");
f.createNewFile();
System.out.println("getName:"+f.getName());//a.txt
System.out.println("getPath:"+f.getPath());//a.txt
System.out.println("getAbsolutePath:"+f.getAbsolutePath());//D:\JAVA\a.txt
System.out.println("getParent:"+f.getParent());//null
static File[] listRoots():获取该系统中有效的盘符。
String[] list():获取指定目录下当前所有的文件及文件夹的名称。
String[] list(FilenameFilter filter):获取被指定过滤器过滤后的文件及文件夹的名称。
File[] listFiles():获取指定目录下的文件及文件夹的对象。
File f=new File("a.txt");
f.createNewFile();
//文件列表1
File dir1=new File("c:\\");
String[] names=dir1.list();
//有效盘符列表
File[] files=File.listRoots();
//文件列表2
File dir2=new File("c:\\");
File[] files=dir2.listFiles();
//有过滤规则的文件列表
File dir3=new File("c:\\");
String[] names=dir3.list(new FilenameFilter()
{
public boolean accept(File dir,String name)
{
return name.endsWith("*.bmp");
}
});
5)重命名
renameTo(File f),例如,
File f1=new File("c:\\a.txt");
File f2=new File("c:\\b.txt");
f1.renameTo(f2); //将c盘下的a.txt文件改名为b.txt文件
4、递归
其实就是在使用一个功能过程中,又对该功能有需求,就出现了函数调用自身的情况,而这就是递归。
注意:
1)一定要限定条件,否则内存溢出。
2)使用递归时,调用次数不要过多,否则也会出现内存溢出。
例1:利用递归列出指定目录下的所有文件及文件夹中的文件(子文件)
import java.io.*;
class Test
{
public static void main(String[] args) throws IOException
{
File dir=new File("e:\\Youku Files");
listDir(dir,0);
}
public static void listDir(File dir,int level)
{
System.out.println(getLevel(level)+dir.getName());
level++;
File[] files=dir.listFiles();
for (File file:files)
{
if(file.isFile())//如果是文件,打印出来
System.out.println(getLevel(level)+file.getName());
else //如果是文件夹,递归调用listDir()
listDir(file,level);
}
}
//使列出的目录具有层次
public static String getLevel(int level)
{
StringBuilder sb=new StringBuilder();
sb.append("|--");
for (int x=0;x<level ;x++ )
{
sb.insert(0," ");
}
return sb.toString();
}
}
输出结果:
|--Youku Files
|--download
|--temp
|--transcode
|--youkudisk
|--cache_0.dat
|--cache_1.dat
|--cache_2.dat
|--cache_3.dat
例2:利用递归删除一个带内容的目录
import java.io.*;
class Test
{
public static void main(String[] args) throws IOException
{
File dir=new File("e:\\Youku Files");
removeDir(dir);
}
public static void removeDir(File dir)
{
File[] files=dir.listFiles();
for (int x=0;x<files.length ;x++ )
{
if(files[x].isFile())
files[x].delete();
else
removeDir(files[x]);
}
dir.delete();
}
}
二、Properties
Map
|--Hashtable
|--Properties
Properties是Hashtable的子类,也就是说它具备Map集合的特点,而且它里面存储的键值对都是字符串(因此,Properties不需要泛型)。Properties是与IO技术相结合的集合容器,该对象的特点是可以用于键值对形式的配置文件。
常见方法:
1、存入键值对:setProperty(String key,String value);
2、获取指定键对应的值:String getProperty(String key);
3、获取集合中所有键元素:
Enumeration propertyNames();
JDK1.6提供新方法:Set<String> stringPropertyNames();
4、列出该集合中的所有键值对,可以通过参数打印流指定列出的目的地:
list(PrintStream); list(PrintWriter),例如,
list(System.out):将集合中的键值对打印到控制台;list(new PrintStream("prop.txt")):将集合中的键值对存储到prop.txt文件中。
5、将流中的规则数据加载进集合,并称为键值对:
load(InputStream in);JDK1.6提供新方法:load(Reader r);
注意:流中的数据要求是“键=值”的规则数据。
6、将集合中的数据存储在指定的目的地:
store(OutputStream os,String comment);JDK1.6提供新方法:store(Writer w,String comment)。使用该方法存储时,会带着当时存储的时间。
import java.util.*;
class TestDemo
{
public static void main(String[] args)
{
Properties p=new Properties();
p.setProperty("zhangsan","30");
p.setProperty("lisi","22");
System.out.println("lisi="+p.getProperty("lisi"));//lisi=22
Set<String> names=p.stringPropertyNames();
for(String str:names)
{
System.out.println(str+"="+p.getProperty(str));//zhangsan=30
//lisi=22
}
}
}
例3:记录一个程序运行的次数,当超过指定次数时,该程序不能继续运行
import java.util.*;
import java.io.*;
class TestDemo
{
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(file);
prop.load(fis);
int count=0;
String value=prop.getProperty("Times");
if(value!=null)
{
count=Integer.parseInt(value);
if(count>=5)
{
System.out.println("抱歉,使用次数已到,您不能继续使用!");
return;
}
}
count++;
prop.setProperty("Times",count+"");
FileOutputStream fos=new FileOutputStream(file);
prop.store(fos,"");
fis.close();
fos.close();
}
}
三、打印流
该流提供了打印方法,可以将各种数据类型的数据都原样打印。
1、PrintStream:是一个字节打印流,System.out对应的类型就是printStream。它的构造函数可以接收三种数据类型的值。
1)字符串路径;2)File对象;3)OutputStream。
2、PrintWriter:是一个字符打印流。它的构造函数可以接收四种类型的值。
1)字符串路径;2)File对象;3)OutputStream;4)Writer。
其中,对于1)和2)类型的数据,还可以指定编码表;对于3)和4)类型的数据,可以指定自动刷新。注意:该自动刷新值为true时,只有三个方法可用:println、print、format。
import java.util.*;
import java.io.*;
class TestDemo
{
public static void main(String[] args)throws IOException
{
BufferedReader bufr=
new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw=new PrintWriter(new FileWriter("c:\\1.txt"),true);
String line=null;
while ((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
pw.println(line.toUpperCase());
//pw.flush();
}
pw.close();
bufr.close();
}
}
如果PrintWriter既想要有自动刷新,又可指定编码表,还要提高效率:
PrintWriter pw=
new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(1.txt),"utf-8")),true);
四、序列流
SequenceInputStream,也称为合并流。
特点:可以将多个读取流合并成一个流,这样操作起来很方便。
原理:将每个读取流对象存储到一个集合中,最后一个流对象结尾作为整个流的结尾。
构造函数:
1)SequenceInputStream(InputStream in1,InputStream in2):将两个读取流合并成一个流。
2)SequenceInputStream(Enumeration<? extends InputStream> en):将枚举中的多个流合并成一个流。
作用:用于多个数据的合并。
注意:因为Enumeration是Vector中特有的取出方式。而Vector被ArrayList取代,所以使用ArrayList集合效率更高些。那么,如何获取Enumeration呢?请见下例,
例4:文件的分割与合并
import java.util.*;
import java.io.*;
class TestDemo
{
public static void main(String[] args)throws IOException
{
split();
merge();
}
//合并文件
public static void merge()throws IOException
{
ArrayList<FileInputStream> al=new ArrayList<FileInputStream>();
for (int x=1;x<=51 ;x++ )
{
al.add(new FileInputStream("c:\\splitfiles\\"+x+".part"));
}
final Iterator<FileInputStream> it=al.iterator();
//以匿名内部类的形式,用Iterator的方法取得Enumeration
Enumeration<FileInputStream> en=new Enumeration<FileInputStream>()
{
public boolean hasMoreElements()
{
return it.hasNext();
}
public FileInputStream nextElement()
{
return it.next();
}
};
//多个流变成了一个流
SequenceInputStream sis=new SequenceInputStream(en);
FileOutputStream fos=new FileOutputStream("c:\\splitfiles\\0.JPG");
byte[] buf=new byte[1024];
int len=0;
while ((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
//分割文件
public static void split()throws IOException
{
FileInputStream fis=new FileInputStream("c:\\1.JPG");
FileOutputStream fos=null;
byte[] buf=new byte[1024];
int len=0,count=1;
while ((len=fis.read(buf))!=-1)
{
//每次形成一个1Kb的part文件
fos=new FileOutputStream("c:\\splitfiles\\"+(count++)+".part");
fos.write(buf,0,len);
fos.close();
}
fis.close();
}
}
五、对象的序列化
ObjectInputStream\ObjcetOutputStream
可以通过这两个流对象直接操作已有对象,并将对象进行本地持久化存储。存储后的对象可以进行网络传输。
特有方法:
ObjectInputStream:
Object readObject():该方法抛出ClassNotFoundException。
ObjectOutputStream:
void writeObject(Object):被写入的对象必须实现Serializable接口,否则会抛出NotSerializableException。
public static void writeObj()throws IOException
{
ObjectOutputStream oos=
new ObjectOutputStream(new FileOutputStream("obj.txt"));
oos.writeObject(new Person("lisi",39));
oos.close();
}
public static void readObj()throws IOException
{
ObjectInputStream ois=
new ObjectInputStream(new FileInputStream("obj.txt"));
Person p=(Person)ois.readObject();
System.out.println(p);
ois.close();
}
Serializable:该接口其实就是一个没有方法的标记接口。
用于给类指定一个UID。该UID是通过类中的可序列化成员的数字签名运算出来的一个long型值。只要这些成员没有变化,那么该值每次运算都一样。
该值用于判断被序列化的对象和类文件是否兼容。如果被序列化的对象需要被不同的类版本所兼容,可以在类中自定义UID。
定义方式:static final long serialVersionUID=42L;
注意:静态成员变量,不会被序列化;非静态成员若不想被序列化,可用transient关键字修饰。
六、管道流
PipedInputStream\PipedOutputStream
特点:读取管道流和写入管道流可以进行连接。
通常这两个流在使用时,需要加入多线程技术,也就是让读写同时运行。注意:对于read方法,该方法是阻塞式的,也就是没有数据的情况下该方法会一直等待。
例5:多线程下的管道流实例
import java.io.*;
class Test
{
public static void main(String[] args) throws IOException
{
PipedInputStream pis=new PipedInputStream();
PipedOutputStream pos=new PipedOutputStream();
pis.connect(pos);//读取管道流与写入管道流连接
Read r=new Read(pis);
Write w=new Write(pos);
new Thread(r).start();
new Thread(w).start();
}
}
class Read implements Runnable
{
private PipedInputStream pis;
Read(PipedInputStream pis)
{
this.pis=pis;
}
public void run()
{
try
{
byte[] buf=new byte[1024];
int len=pis.read(buf);
String str=new String(buf,0,len);
System.out.println("pis:"+str);
pis.close();
}
catch (IOException e)
{
System.out.println(e.toString());
}
}
}
class Write implements Runnable
{
private PipedOutputStream pos;
Write(PipedOutputStream pos)
{
this.pos=pos;
}
public void run()
{
try
{
pos.write("pos is coming!".getBytes());
pos.close();
}
catch (IOException e)
{
System.out.println(e.toString());
}
}
}
输出结果:
pis:pos is coming!
七、RandomAccessFile
该对象不是流体系中的一员。该对象中封装了字节流,同时还封装了一个缓冲区(字节数组),通过内部的指针来操作数组中的数据。
特点:
1)该对象只能操作文件,所以构造函数接收两种类型的参数:a.字符串路径;b.File对象。
2)该对象既可以对文件进行读取,也可以写入。在进行对象实例化时,必须要指定该对象的操作模式,r\rw等。
r:只读模式,不会创建文件,会去读取一个已存在的文件。如果该文件不存在,则发生异常。
rw:若操作的文件不存在,会自动创建;若存在则不会覆盖。
常用方法:
skipBytes(int n):跳过指定的字节数。
seek(long pos):指定指针的位置。
getFilePointer():获取指针位置。
该对象中有可以直接操作基本数据类型的方法,如,
readInt() \ readByte() \ writeInt() \ writeByte()等。
该对象既可以读数据,也可以写数据,而且想读哪里就读哪里,想往哪里写就往哪里写。如果写入位置已有数据,会发生数据覆盖,即可以对数据进行修改。
在使用该对象时,建议数据都是规则的,或者是分段的。
可以用于多线程的下载,也就是通过多线程往一个文件中同时存储。
例6:RandomAccessFile读写实例
import java.io.*;
class Test
{
public static void main(String[] args) throws IOException
{
writeFile();
readFile();
}
public static void readFile()throws IOException
{
RandomAccessFile raf=new RandomAccessFile("c:\\1.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("c:\\1.txt","rw");
raf.write("李四".getBytes());
raf.writeInt(33);
raf.write("王五".getBytes());
raf.writeInt(22);
raf.close();
}
}
输出结果:
name=王五
age=22
八、操作基本数据类型的流对象
DataInputStream: DataInputStream(InputStream is);
操作基本数据类型的方法:
int readInt():一次读取四个字节,并将其转成int值。
boolean readBoolean():一次读取一个字节。
short readShort():一次读取两个字节。
long readLong():一次读取八个字节。
String readUTF():按照utf-8修改版读取字符。注意:它只能读writeUTF()写入的字符数据。
DataOutputStream:DataOutputStream(OutputStream os);
操作基本数据类型的方法:
writeInt(int i):一次写入四个字节。注意,与write(int i)不同,write(int i)只将该整数的最低一个8位写入,剩余三个8位丢弃。
writeBoolean(boolean b );
writeShort(short s);
writeLong(long l);
writeUTF(String str):按照utf-8修改版将字符数据进行存储,只能通过readUTF()读取。
通常只要操作基本数据类型的数据,就需要这两个流。通常成对使用。
例7:操作基本数据类型流的读写实例
import java.io.*;
class Test
{
public static void main(String[] args) throws IOException
{
writeData();
readData();
}
public static void writeData()throws IOException
{
DataOutputStream dos=new DataOutputStream(new FileOutputStream("c:\\1.txt"));
dos.writeInt(123);
dos.writeBoolean(true);
dos.writeDouble(11.22);
dos.close();
}
public static void readData()throws IOException
{
DataInputStream dis=new DataInputStream(new FileInputStream("c:\\1.txt"));
int i=dis.readInt();
boolean b=dis.readBoolean();
double d=dis.readDouble();
System.out.println("int num="+i);
System.out.println("boolean b="+b);
System.out.println("double d="+d);
}
}
输出结果:
int num=123
boolean b=true
double d=11.22
九、操作数组的流对象
1、操作字节数组
ByteArrayInputStream
ByteArrayOutputStream:
toByteArray();
toString();
writeTo(OutputStream os);
2、操作字符数组
CharArrayReader\CharArrayWriter
对于这些流,源是内存,目的也是内存。
这些流并未调用系统资源,使用的就是内存中的数组,所以这些流在使用的时候不需要close()。
操作数组的读取流在构造的时候,必须要明确一个数据源,所以要传入相对应的数组;操作数组的写入流在构造时可以使用空参数,因为它内置了一个可变长度数组作为缓冲区。
这些流的出现其实就是通过流的读写思想来操作数组。
import java.io.*;
class Test
{
public static void main(String[] args) throws IOException
{
//数据源,必须传入一个字节数组
ByteArrayInputStream bis=new ByteArrayInputStream("ABC".getBytes());
//数据目的,不必定义数据目的,因为已经内置了可变长度的字节数组
ByteArrayOutputStream bos=new ByteArrayOutputStream();
int by=0;
while ((by=bis.read())!=-1)
{
bos.write(by);
}
System.out.println(bos.size()); //3
System.out.println(bos.toString());//ABC
bos.writeTo(new FileOutputStream("c:\\1.txt"));//1.txt文件中写入了ABC
}
}
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------详细请查看:www.itheima.com