JavaSE基础:IO

来源:互联网 发布:网络诽谤司法解释 编辑:程序博客网 时间:2024/06/01 07:49

  ------- android培训、java培训、期待与您交流! ----------

IO流分类

按流向:输入流、输出流;
按数据:字节流,字符流。
基类:
字节流:InputStream;OutPutStream
字符流:Reader;Writer;


字符流

数据的最常见体现形式是文件,先以操作文件为主来演示,需求:在硬盘上创建一个文件,并写入文字数据。

Writer——OutputStreamWriter——FileWriter

方法:
    write(str /字符/字符数组/) 方法:将字符串写入到缓冲
    flush()方法:刷新流对象中的缓冲的数据,将数据刷入到目的地中;
    close()方法:关闭流资源,关闭前刷新流,将数据存入目的地中。
如果文件创建成功,一定要执行close方法关闭资源,需要捕捉IO异常;
FileWriter(File file, boolean append) 根据给定的 File 对象构造一个FileWriter对象
windows下的换行是   \r\n  linux下是\n;


Reader——InputStreamReader——FileReader

方法:
    read(), 从输入流获取一个字符并作为数字返回,读到末尾,返回-1;
    
小程序,读取文件 输出到命令窗口;复制文件。
使用字符数组作为缓冲区,注意捕捉异常 。读写完毕,在finally中关闭流。


——————————————————


缓冲流:提高了对数据的读写效率。

    BufferedWriter
    BufferedReader
缓冲区要结合流才能使用,再流的基础上对流的功能进行了增强。


关闭缓冲区就可以关闭缓冲区中的流对象,只要关闭缓冲区即可。
newLine()方法
BufferedReader  字符读取缓冲流
    readLine()读取一行;


小练习:使用缓冲区复制一个文件。
        自定义读取缓冲区,读取一行的方法。
LineNumberReader


装饰设计模式

    当要对已有的对象进行功能增强时,可以定义一个类,将已有的对象传入,给予已有功能,
    并提供加强功能,那么自定义的该类就称为装饰类。
    BufferReader其实就是装饰设计模式的体现。   readLine方法。
    装饰类通常通过构造方法接收被装饰的对象,并给予被装饰对象提供更强的功能。


装饰模式比继承灵活,避免了继承的臃肿,降低了类与类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的相同,只不过提供了增强功能,所以装饰类和被装饰类属于一个体系。


字节流

    InputStream
    OutputStream


FileOutputStream fos = new FileOutputStream("xxxx.txt") ;
fos.write("abcdef".getBytes()) ;  //字符串转为字节数组
//不需要刷新缓冲区,就可以写入数据,但是要关闭资源
fos.close() ;


FileInputStream  fis = new FileInputStream("dddd.dd")  ;
byte[] buf = new byte[fis.available()] ;  //available 方法返回下一步可读取的字符数,换行符是两个字符
//返回一个刚刚好的缓冲区,不用循环了,这种方法比较危险,一般定义 byte[1024]
fis.read(buf) ;
System.out.println(new String(buf)) ;
fis.close() ;
————————————————————

缓冲区

    BufferedInputStream
    BufferedOutputStream


标准输入输出

FileInputStream in = System.in ;
int by = in.read();


字节流转换字符流:  

InputStreamReader
    InputStreamReader sdr = new InputStreamReader(in) ;
    BufferedReader br = new BufferedReader(sdr) ;
    br.readline();

字符到字节流的桥梁

OutputStreamWriter
    FileOutputStream  fos = System.out ;
    OutputStreamWriter osw = new OutputStreamWriter(fos) ;
    BufferedWriter bw = new BufferedWriter(osw) ;
    bw.write(str );
    bw.newLine() ; //加上换行
    bw.flush() ; 


键盘录入最常见写法。

    1、键盘录入,输出控制台;
    2、键盘录入,输出文件;
    3、读取文件,输出控制台。


流操作的基本规律:

该用哪一个流对象?    
    1、明确源和目的;
            源:输入流     InputStream    Reader
            目的:输出流    OutputStream    Writer
    2、明确操作的数据是不是纯文本。
            纯文本:字符流    Reader    Writer
            非纯文本:字节流    InputStream    OutputStream
    3、体系明确后,在确定使用那个具体的对象
            通过设备区分:
            源设备:内存,硬盘,键盘
            目的设备:内存,硬盘,控制台




File类

方法:

1、创建:
    boolean creatNewFile();    在指定位置上创建文件,如果文件存在,返回false
        和输出流不同,输出流对象已建立就创建文件,如果文件存在,覆盖。
    static File creatTempFile(xxx, xx);  创建临时文件
    boolean mkdir("xx");  创建目录
    boolean mkdirs("xx\\xx\\xx");  创建多级目录
2、删除
    boolean delete();  删除文件,成功返回true 。    
    deleteOnExit();  退出时删除
3、判断
    boolean exists();  判断是否存在
    boolean isDirectory(File);  判断是否为目录,必须先判断是否存在
    boolean isFile(File);    判断是否为文件,必须先判断是否存在
    boolean isHidden();  判断是否隐藏
    boolean isAbsolute();  判断是相对路径或绝对路径。
4、获取信息
    getName();
    getParent(); //返回绝对路径中的文件父目录
    getPath();
    String  getAbsolutePath();获取绝对路径
    File  getAbsoluteFile();返回对象
    long length();返回占用字节
    long lastModified();获取最后修改时间;
long time = file.lastModified();
Date date = new Date(time);
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);
String strTime = df.format(date); 
可以通过独立进程监控修改时间,如果被修改,通知程序加载新文件。   


5、boolean  renameTo(File dest);  重命名; 将文件重命名为dest,类似于剪切。
    
6、List
    static  File[]  listRoots();  列出系统根目录 如C:\   D:\   
    String[]  list(); 返回文件目录下的文件和文件名,,包括隐藏文件(一级目录),如果是文件,返回空,必须是目录。该目录必须存在。
    Stringlist (FilenameFilter ff);  按文件名过滤;
    |---FilenameFilter接口,重写方法 boolean  accept(File dir,String name) ;
    File[]  listFiles();返回当前目录下的文件或目录的对象。
    File[]  listFiles(FileFilter filter);按文件过滤;


练习:删除一个带内容的目录:

在windows中,删除目录是从里面往外面删除的。
public class RemoveDirTest {public static void main(String[] args) {File dir  = new File("e:\\demodir");removeDir(dir);}public static void removeDir(File dir) {File[] files = dir.listFiles();for(File file : files){if(file.isDirectory()){removeDir(file);}else{System.out.println(file+":"+file.delete());}}System.out.println(dir+":"+dir.delete());}}


练习:遍历文件目录,将指定格式文件目录存储到一个文本列表。

递归:函数直接或间接的调用自身
public class FileTest {public static void main(String[] args) {File dir = new File("d:\\java\\workspace");listAll(dir,0);}public static void listAll(File dir,int level) {System.out.println(getSpace(level)+dir.getName());//获取指定目录下当前的所有文件夹或者文件对象level++;File[] files = dir.listFiles(new FileFilter(){@Overridepublic boolean accept(File pathname) {return pathname.isDirectory()||pathname.getName().endsWith(".java");}});/*FilenameFilter filter = new FilenameFilter(){@Overridepublic boolean accept(File dir, String name) {return name.endsWith(".java");}};filter.accept(dir,file.getName());//过滤的另一种方式*/for(int x=0; x<files.length; x++){if(files[x].isDirectory()){listAll(files[x],level);}elseSystem.out.println(getSpace(level)+files[x].getName());}}private static String getSpace(int level) {StringBuilder sb = new StringBuilder();for(int x=0; x<level; x++){sb.append("   ");}sb.append("|--");return sb.toString();}}


Properties

Properties 是hashTable的子类,具备map集合的特点,键值对是字符串,是集合和IO相结合的容器,可以用于键值对形式的配置文件。
在加载数据时,需要数据有固定格式,也就是键——值;
    load(in); store(out,comments);comments为配置文件的首行说明文字,只能是英文字符


练习题:用于记录应用程序运行次数,如果次数已到,那么给出注册提示。

    需要一个配置文件用于记录软件的使用次数。使用Properties配置文件可以实现应用程序数据的共享。            
public class PropertiesTest {public static void main(String[] args) throws IOException  {getAppCount();}public static void getAppCount() throws IOException{//将配置文件封装成File对象。File confile = new File("count.properties");if(!confile.exists()){confile.createNewFile();}FileInputStream fis = new FileInputStream(confile);Properties prop = new Properties();prop.load(fis);//从集合中通过键获取次数。String value = prop.getProperty("time");//定义计数器。记录获取到的次数。int count =0;if(value!=null){count = Integer.parseInt(value);if(count>=5){throw new RuntimeException("使用次数已到,请注册,给钱!");}}count++;//将改变后的次数重新存储到集合中。prop.setProperty("time", count+"");FileOutputStream fos = new FileOutputStream(confile);prop.store(fos, "");fos.close();fis.close();}}            





打印流:

print()方法可以将各种数据和数据类型原样打印。不会抛出IOException.
    构造函数可以接受的数据类型,如果目标是输出流,可以加自动刷新标记

PrintStream    字节打印流    

    1、File对象    File
    2、字符串路径    String
    3、字节输出流    OutputStream

PrintWriter    字符打印流

    1、File对象    File
    2、字符串路径    String
    3、字节输出流    OutputStream  
    4、字符输出流    Writer
特殊:write(int)方法:将int最低八位输出




读取键盘:

    BufferedReader bufr = new BufferedReader (new InputStreamReader(System.in))   ;

序列输入流

SequenceInputStream(Enmuration<InputStream> en)
构造方法将多个读取流合并为一个读取流。

示例

public class SequenceInputStreamDemo {public static void main(String[] args) throws IOException {//需求:将1.txt 2.txt 3.txt文件中的数据合并到一个文件中。/* Vector<FileInputStream> v = new Vector<FileInputStream>();v.add(new FileInputStream("1.txt"));v.add(new FileInputStream("2.txt"));v.add(new FileInputStream("3.txt"));Enumeration<FileInputStream> en = v.elements();//---Vector的elements()方法返回该集合的枚举*/ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();for(int x=1; x<=3; x++){al.add(new FileInputStream(x+".txt"));}Enumeration<FileInputStream> en = Collections.enumeration(al);//---使用集合工具类的enumeration(Collection col)方法返回枚举./*final Iterator<FileInputStream> it = al.iterator();   //---局部内部类只能访问被final修饰的局部变量Enumeration<FileInputStream> en = new Enumeration<FileInputStream>(){//---自定义枚举@Overridepublic boolean hasMoreElements() {return it.hasNext();}@Overridepublic FileInputStream nextElement() {return it.next();}};*/SequenceInputStream sis = new SequenceInputStream(en);FileOutputStream fos = new FileOutputStream("1234.txt");byte[] buf = new byte[1024];int len = 0;while((len=sis.read(buf))!=-1){fos.write(buf,0,len);}fos.close();sis.close();}}




练习切割合并文件:

public class MergeFile {//---合并dir目录下的文件public static void main(String[] args) throws IOException {File dir = new File("c:\\partfiles");mergeFile(dir);}public static void mergeFile(File dir) throws IOException {//---合并文件    //获取指定目录下的配置文件对象。File[] files = dir.listFiles(new SuffixFilter(".properties"));if(files.length!=1)throw new RuntimeException(dir+",该目录下没有properties扩展名的文件或者不唯一");File confile = files[0];//获取文件中配置信息:合并文件名,文件个数==================================Properties prop = new Properties();FileInputStream fis = new FileInputStream(confile);prop.load(fis);String filename = prop.getProperty("filename");int count = Integer.parseInt(prop.getProperty("partcount"));//获取该目录下的所有碎片文件。 ==============================================File[] partFiles = dir.listFiles(new SuffixFilter(".part"));if(partFiles.length!=(count-1)){throw new RuntimeException(" 碎片文件不符合要求,个数不对!应该"+count+"个");}//将碎片文件和流对象关联 并存储到集合中。 ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();for(int x=0; x<partFiles.length; x++){al.add(new FileInputStream(partFiles[x]));}//将多个流合并成一个序列流。 Enumeration<FileInputStream> en = Collections.enumeration(al);SequenceInputStream sis = new SequenceInputStream(en);FileOutputStream fos = new FileOutputStream(new File(dir,filename));byte[] buf = new byte[1024];int len = 0;while((len=sis.read(buf))!=-1){fos.write(buf,0,len);}fos.close();sis.close();}}public class SuffixFilter implements FilenameFilter {private String suffix;public SuffixFilter(String suffix) {super();this.suffix = suffix;}@Overridepublic boolean accept(File dir, String name) {return name.endsWith(suffix);}}public class SplitFileDemo {//---切割文件,并将信息保存到配置文件中private static final int SIZE = 1024 * 1024;public static void main(String[] args) throws Exception {File file = new File("c:\\aa.mp3");splitFile(file);}private static void splitFile(File file) throws IOException {// 用读取流关联源文件。FileInputStream fis = new FileInputStream(file);// 定义一个1M的缓冲区。byte[] buf = new byte[SIZE];// 创建目的。FileOutputStream fos = null;int len = 0;int count = 1;/* * 切割文件时,必须记录住被切割文件的名称,以及切割出来碎片文件的个数。 以方便于合并。 * 这个信息为了进行描述,使用键值对的方式。用到了properties对象  */Properties prop  = new Properties();File dir = new File("c:\\partfiles");if (!dir.exists())dir.mkdirs();while ((len = fis.read(buf)) != -1) {fos = new FileOutputStream(new File(dir, (count++) + ".part"));fos.write(buf, 0, len);fos.close();}//将被切割文件的信息保存到prop集合中。prop.setProperty("partcount", count+"");prop.setProperty("filename", file.getName());fos = new FileOutputStream(new File(dir,count+".properties"));//将prop集合中的数据存储到文件中。 prop.store(fos, "save file info");fos.close();fis.close();}}

对象流

ObjectInputStream 对象的反序列化
ObjectOutputStream 对象序列化
对象序列化需要实现 Serializable 接口,可以指定序列化的版本号:
    private static final long serialVersionUID = 1l;
static静态成员不能被序列化。只能序列化堆内存中的数据。
transient修饰符:瞬态化成员变量,使非静态成员不被序列化。


RandomAccessFile 随机访问文件类;

不算IO体系中的子类,直接继承自Object。
具备读写功能,内部封装了一个数组,通过指针对数组中的元素操作,
可以通过getFilePointer获取指针位置,同时根据seek设置指针位置。
原理是其内部封装了字节读取流和输入流。


构造方法只能操作文件。
RandomAccessFile(File ,'r/rw');rw 代表读写模式
应用:断点续传功能


管道流

PipedInputStream / PipedOutputStream 
PipedReader / PipedWriter 
connect(Piped)连接管道流
需要使用多线程操作。

示例

public class PipedStream {public static void main(String[] args) throws IOException {PipedInputStream input = new PipedInputStream();PipedOutputStream output = new PipedOutputStream();input.connect(output);new Thread(new Input(input)).start();new Thread(new Output(output)).start();}}class Input implements Runnable{private PipedInputStream in;Input(PipedInputStream in){this.in = in;}public void run(){try {byte[] buf = new byte[1024];int len = in.read(buf);String s = new String(buf,0,len);System.out.println("s="+s);in.close();} catch (Exception e) {}}}class Output implements Runnable{private PipedOutputStream out;Output(PipedOutputStream out){this.out = out;}public void run(){try {Thread.sleep(5000);out.write("hi,管道来了!".getBytes());} catch (Exception e) {}}}

可以操作基本数据类型的流对象 

DataOutputStream(OutputStream out) 创建一个新的数据输出流,将数据写入指定基础输出流。
DataInputStream(InputStream in) 使用指定的底层 InputStream 创建一个 DataInputStream。
写入UTF的方法:writeUTF("数据流");  读取只能使用readUTF();


操作字节数组流

ByteArrayInputStream(byte[] buf) 创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。
ByteArrayOutputStream() 创建一个新的 byte 数组输出流.通过toByteArray()和toString()获取数据.
close()方法无效;不会产生IOException;
writeTo(OutputStream out);将此 byte 数组输出流的全部内容写入到指定的输出流中。
用流的思想操作数组


操作字符数组
CharArrayReader
CharArrayWriter


操作字符串
StringReader
StringWriter


编码表

String str = new String("呵呵","UTF-8");
byte[] buf = str.getBytes("UTF-8");

示例

public class Test {public static void main(String[] args) throws IOException {String str = "ab你好cd谢谢";//int len = str.getBytes("gbk").length;//for(int x=0; x<len; x++){//System.out.println("截取"+(x+1)+"个字节结果是:"+cutStringByByte(str, x+1));//}int len = str.getBytes("utf-8").length;for(int x=0; x<len; x++){System.out.println("截取"+(x+1)+"个字节结果是:"+cutStringByU8Byte(str, x+1));}}public static String cutStringByU8Byte(String str, int len) throws IOException {byte[] buf = str.getBytes("utf-8");int count = 0;for(int x=len-1; x>=0; x--){  //---判断截取的最后几位是什么字符。if(buf[x]<0)count++;elsebreak;}if(count%3==0)   //---UTF-8的汉字是3个负数return new String(buf,0,len,"utf-8");else if(count%3==1)return new String(buf,0,len-1,"utf-8");else return new String(buf,0,len-2,"utf-8");}public static String cutStringByByte(String str,int len) throws IOException{byte[] buf = str.getBytes("gbk");int count = 0;for(int x=len-1; x>=0; x--){if(buf[x]<0)count++;elsebreak;}if(count%2==0)return new String(buf,0,len,"gbk");elsereturn new String(buf,0,len-1,"gbk");}}

------- android培训、java培训、期待与您交流! ----------
          

原创粉丝点击