随笔-159  评论-114  文章-7  trackbacks-0
需求,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)  编辑  收藏 所属分类: 达内学习总结

只有注册用户登录后才能发表评论。


网站导航: