需求,java程序与外届交流数据。
实际上是OS与JVM内存交互数据。
那么针对程序,有输出流,也有输入流。
java.io包下,File类,它表示文件系统上的一个文件或者目录。
方法,总体来说是对磁盘文件的磁盘操作,不能看内容,主要是为了获得文件和文件属性。
File dir = new File("d:\");
File f = new File(dir,"11.txt");// -->创建文件对象,只是一个对象,没有反映到磁盘上。
f.createNewFile();//-->创建文件
f.mkdir();//创建目录
delete();调用完马上就删除了
deleteOnExit();程序退出时,可以作为临时文件。
new File("d:\\....\\11.txt");
File.separator
file.list() 所有文件名 String[]
file.listFiles() File[]数组
注意如何实现 dir *.java的效果呢,需要一个过滤器
public
File[]
listFiles(
FilenameFilter filter)
public
File[]
listFiles(
FileFilter filter)
FilenameFilter需要实现
boolean
accept(
File dir,
String name)
返回true,表示要包含在结果中的
new FilenameFilter(){
public boolean acccept(File dir,String name)
{
if(name.indexOf(".java") == -1) return false;
else return true;
}
}
===================================
File类不能读取文件内容。
所以真正读取文件内容,需要在虚拟机中的对象和DS数据源之间建立一个数据输入输出流。
按照以JVM为方向,数据流向分为输入流,输出流。
按照传输数据单元:又有字节流和字符流。8位为一字节。
按功能又叫做节点流,比如专门以文件为数据源与程序建立的数据流,通道,就是FileInputStream。
给节点流,添加辅助功能的流,也就是构造方法的参数为其他流的流,一定是过滤流。(装饰模式应用)
所有字节输入流的父类,都是InputStream。比如有子类,FileInputStream,还有javax.sound.sampled.AudioInputStream
它有一个
read()方法,一次读入一个字节,由于是跨出JVM的操作,因此极其消耗资源。
所以一般用
read(byte[] b),给一个字节数组,方法返回,字节数据会读满,返回值为实际,读入的字节数,用于处理,最后一次时,可能并没有装满,要保证文件一个字节都不差,必须争取取出相应个数的字节内容。返回-1,表示没有可以读的了。
read(byte[] b, int off, int len),从数组off起始位置读入,len试图读入的个数。可控的。
read(b) <==> read(b,0,b.length);
OutputStream
write(int b) -> 写一个字节
由于输入、输出流是跨出虚拟机边界的资源,虚拟机很难回收,这时对于资源的占用,是一种极大的浪费。
就好像,你能让你妈帮你收拾屋子,洗衣服,但是你打开水龙口,打完水不管水龙头,试一试。
或者你在麦当劳吃完饭,盘子放那,有服务生来帮你收走,但你试试把盘子拿到大街上,放在外面,服务生是不能回收的。
虽然Java帮你回收不使用的对象,但对于关闭输入输出流的工作,程序员是要自己负责!因为跨出虚拟机边界,虚拟机不管。
============================
节点流,FileInputStream,当然也是字节流。有Stream,只是记忆方便。
构造器参数,文件名,文件对象File
FileInputStream fi = new FileInputStream("1.txt");
byte b[] = new byte[100];
int length;
while((length = (fi.read(b))!=-1){
String s = new String(b);
System.out.println(s);
}
fi.close();
FileOutputSteam(File file,boolean append)//第二个选项,为true,表示要追加文件内容。
构造器一个FileOutputStream对象时,磁盘会同时生成一个文件(如果已存在同名文件,会先删除)FileOutputSteam fo = new FileOutputStream("1.txt",true);
String s = new String("hi my girl");
byte[] b = s.getBytes();
while(fo.write(b)!= -1){};
fo.close();
为了能够轻松的将简单数据类型的数据,直接输出到流中,需要对已存在字节输出流添加功能。
所以这种流叫做过滤流,例如java.io.DataOutputStream。它的构造函数参数为OutputStream对象。
FileOutputStream file = new FileOutputStream("DST1.txt");
DataOutputStream out = new DataOutputStream(file);
out.writeUTF(str);
注意使用这个过滤流,输出和输入的顺序要一致。
输出:
_byte_ _short_ _ _ _int
输入:
不能够
_ _short_ byte_ _ _ _
这样读,会将byte和short的前一个字节一起读为short类型,显然是错误的。
=================================
给输入输出流添加缓冲功能的过滤流,叫做BufferedOutputStream out = new BufferedOutputStream(other outputstream);
虚拟机中拿出一个块区域当作缓冲区,把数据先写入缓冲区,如果缓冲区满了,再一次性将内容写到磁盘。
大大的减少了虚拟机快越边界的操作,效率大幅度提高。是牺牲空间换时间的典型做法。
任何带缓冲的流,都会有一个flush()的方法,可以不管缓冲区满不满,都情空缓冲区。
还有直接调用.close,也会自动调用.flush()方法。
对于过滤流,只关闭最外层的流,即可。
===============================
管道,节点流
PipedOutputStream / PipedInputStream
pos.connect(pis);
用于给两个线程交换数据。
import java.io.*;
public class PipedStreamTest
{
public static void main(String[] args)
{
PipedOutputStream pos=new PipedOutputStream();
PipedInputStream pis=new PipedInputStream();
try
{
pos.connect(pis);
new Producer(pos).start();
new Consumer(pis).start();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
class Producer extends Thread
{
private PipedOutputStream pos;
public Producer(PipedOutputStream pos)
{
this.pos=pos;
}
public void run()
{
try
{
pos.write("Hello,welcome you!".getBytes());
pos.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
class Consumer extends Thread
{
private PipedInputStream pis;
public Consumer(PipedInputStream pis)
{
this.pis=pis;
}
public void run()
{
try
{
byte[] buf=new byte[100];
int len=pis.read(buf);
System.out.println(new String(buf,0,len));
pis.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
} 练习实现,文件拷贝功能,条件一个字节都能看,比如PDF,备份文件可以看,电影图片都可以正常读取。
import java.io.*;
public class TestFileCopy{
public static void main(String[] args){
BufferedInputStream in=null;
BufferedOutputStream out=null;
try{
in=new BufferedInputStream(new FileInputStream(args[0]));
out=new BufferedOutputStream(new FileOutputStream(args[1]));
byte[] b=new byte[1024];
int len;
while((len=in.read(b))!=-1){
out.write(b,0,len);
}
out.flush();
}
catch(Exception e){
e.printStackTrace();
}
finally{
if (in!=null){
try{
in.close();
}
catch(Exception e){}
}
if (out!=null){
try{
out.close();
}
catch(Exception e){}
}
}
}
} 注意,out.write(b,0,len);保证了最后一次,b没有装满时,可以只写装入的数据。
==============================
字符流
java.io.Reader
java.io.Writer
单位为字符,一次一个字符,主要对于纯文本。
read(char[] cbuf)
基本方法,参数为字符数组,而不是字节数组。一个字符2字节。
FileReader,字符文件输入流。
那么一个字符有什么存在意义呢,
'A'影射编码成为整数65,而反过来,整数解码成为'A'。如果编解码不统一就会出现乱码。
ASCii,包括数字和字符,一个字节,256个字符
这是最早的编码,所以以后的任何编码都兼容ASCii,所以英文总没有问题。
ISO-8859-1,一个字节 1B
GB2312,国标,2B,65535,‘喆’就不这个字符集中,只有常用汉字。
GBK,2B。包含所有汉字。
UNICODE 2B
UTF-8,不一定占用几个字节。
解决乱码问题的宗旨,就是保证编码解码方式一致。
---------------------------
java.io.InputStreamReader
InputStreamReader(InputStream in)
这是一个字符流,而构造函数参数是一个字节流。
通常称之为从字节六到字符流的桥转换。
InputStreamReader(InputStream in, String charsetName)
第二个参数就是编码方式参数,指对字节流按照什么解码方式将文件读入。
OutputStreamWriter(OutputStream out, String charsetName)
输出是指按什么编码方式输出字节流。
import java.io.*;
public class TestReaderWriter{
static void write() throws Exception
{
FileOutputStream fos = new FileOutputStream("test.dat");
OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");
BufferedWriter out = new BufferedWriter(osw);
out.write("慢慢炉火纯青了!");
out.newLine();
out.write("学完C++,Java确实很简单,但很棒!");
out.flush();
}
static void read() throws Exception
{
FileInputStream fis = new FileInputStream("test.dat");
InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
BufferedReader in = new BufferedReader(isr);
String line;
while((line = in.readLine())!=null)
{
System.out.println(line);
}
}
public static void main(String[] args) throws Exception
{
write();
read();
System.out.println(System.getProperty("file.encoding"));
}
} PrintWriter,也是一个带缓冲的字符输出流,可以直接由一个OutputStream或者Writer构造,但功能更强大,也就是方法更多。
PrintWriter(OutputStream out, boolean autoFlush)
PrintWriter(Writer out, boolean autoFlush)println(String x)
PrintStream,也是同理,带缓冲的字节输出流,功能比BufferedOutputStream更强。
==========================================
java.io.ObjectOutputStream 过滤流
输出一个对象,是对DataOutputStream的增强。
writeObject(Object obj)
对象序列化,对象需要实现Serializable接口,这个接口是一个标记接口。
由于对象有价值的东西就是属性,所以只关系对象的属性文件,如果某个属性没有序列化的意义,那么就用transient修饰,表示不持久化该属性。
恢复时,为默认属性。
要求属性也是Serializable的。
用命令serialver判断一个类是否可以序列化。
=====================================
早期持久化,就是通过文件存储信息,通过定义特定分割符分开信息。
StringTokenizer st = new StringTokenizer(s,"t");
while(st.hasMoreTokens()){
System.out.println();
}
======================================
void open{
BufferedReader in = null;
try{
FileInputStream fis = new FileInputStream("data");
InputStreamReader ir = new InputStreamReader(fis);
in = new BufferedReader(ir);
}catch(Exception e)
{
}
finally{
if(in!=null)
try{
in.close();
}catch(Exception){}
}
}
posted on 2005-12-25 00:08
北国狼人的BloG 阅读(424)
评论(0) 编辑 收藏 所属分类:
达内学习总结