JAVA基础_IO流

字符流和字节流:

     字节流的两个基类:

     InputStream,OutputStream

      字符流两个基类:

      Reader,Writer    

   ··字符流的Writer:

import java.io.FileWriter;

import java.io.IOException;

public class FileWriterDemo01 {

public static void main(String[] args) throws IOException {

//创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。

//而且该文件会被创建到指定目录下,如果该目录下已有同名文件,将被覆盖。

//其实该步骤就是明确数据要存放的目的地。

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

//调用write方法,将字符串写入流中。

fw.write("abcde");

//刷新流对象中的缓冲中的数据

//将数据存入到目的地中。

//fw.flush();

//关闭流资源,关闭之前会刷新一次内部的缓冲中的数据。将数据刷到目的地。

//和flush区别;flush刷新后,流可以继续使用,close刷新后,会将流关闭。

fw.close();

}

}

  1.  

        IO异常的处理方式:

 

public class IOExceptionDemo {

public static void main(String[] args){

FileWriter fw = null;

try {

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

fw.write("affd");

} catch (IOException e) {

System.out.println(e.toString());

} finally{

try {

if(fw!=null)

fw.close();

} catch (IOException e) {

System.out.println(e.toString());

}

}

}

}

  1.  

        在原有数据的基础上续写(文件的续写):

 

/*

*所用到的方法:

* public FileWriter(String fileName,boolean append)throws IOException

* 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。

*/

import java.io.FileWriter;

import java.io.IOException;

public class FileWriterDemo02 {

public static void main(String[] args){

//传递一个true参数,代表不覆盖已有文件。并在已有文件的末尾处进行数据的续写。

FileWriter fw = null;

try {

fw = new FileWriter("demo.txt",true);

fw.write("你好,\r\n谢谢!");

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally{

try {

if(fw!=null)

fw.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

  1.  

        文件的读取方式(FileReader类):

 

/*

* public int read()throws IOException读取单个字符。

* public int read(char[] cbuf)throws IOException将字符读入数组。

*/

import java.io.FileReader;

import java.io.IOException;

public class FileReaderDemo01 {

public static void main(String[] args){

//创建一个文件读取流对象,和指定名称的文件相关联。

//要保证该文件是已经存在的,如果不存在,会发生FileNOtFoundException

FileReader fr = null;

try {

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

//调用读取流对象的read方法

//read()方法:一次读一个字符,而且会自动王下读。

int num = 0;

while((num = fr.read())!=-1){

System.out.println((char)num);

}

/*

* 方法二: //定义一个字符数组。用于存储读道的字符

* 该read(char[]) 返回的是读到的字符个数

* 定义的数组的大小一般是1024的整数倍

*

* char[] buf = new char[1024];

*

* int num = 0;

* while((num=fr.read(buf))!=-1){

* System.out.println(new String(buf,0,num));

* }

*/

} catch (IOException e) {

e.printStackTrace();

}finally{

try {

if(fr!=null)

fr.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

  1.  

    文件Copy:

 

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

/*

* 复制的原理:

* 其实就是将C盘下的文件数据存储到D盘的一个文件中。

*

* 步骤:

* 1、在D盘中创建一个文件用于存储C盘文件中的数据。

* 2、定义读取流和C盘文件关联。

* 3、通过不断的读写完成数据存储

* 4、关闭资源。

*/

public class CopyTxt {

public static void main(String[] args) {

// copy1();

copy2();

}

public static void copy1(){

FileWriter fw = null;

FileReader fr = null;

try{

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

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

int num = 0;

char[] buf = new char[1024];

while((num = fr.read(buf))!=-1){

fw.write(buf, 0, num);

}

}catch(IOException e){

throw new RuntimeException("Copy Error!");

}finally{

try {

if(fw!=null)

fw.close();

} catch (IOException e) {

throw new RuntimeException("Copy Error!");

}

try {

if(fr!=null)

fr.close();

} catch (IOException e) {

throw new RuntimeException("Copy Error!");

}

}

}

public static void copy2(){

FileWriter fw = null;

FileReader fr = null;

try{

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

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

int num = 0;

while((num = fr.read())!=-1){

fw.write(num);

}

}catch(IOException e){

throw new RuntimeException("Copy Error!");

}finally{

try {

if(fw!=null)

fw.close();

} catch (IOException e) {

throw new RuntimeException("Copy Error!");

}

try {

if(fr!=null)

fr.close();

} catch (IOException e) {

throw new RuntimeException("Copy Error!");

}

}

}

}

  1.  

        字符流缓冲区:BufferedWriter和BufferedReader:      

 

import java.io.BufferedWriter;

import java.io.FileWriter;

import java.io.IOException;

public class BufferedWriterDemo {

/*

* public BufferedWriter(Writer out)创建一个使用默认大小输出缓冲区的缓冲字符输出流。

* newLine() 写入一个换行符。

*/

public static void main(String[] args) throws IOException {

//创建一个字符写入流对象。

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

//为了提高字符写入流的效率。加入了缓冲技术。

//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。

BufferedWriter bufw = new BufferedWriter(fw);

bufw.write("abcde");

//记住,只要用到缓冲区,就要记得刷新

bufw.flush();

//其实关闭缓冲区,就是在关闭流。

bufw.close();

}

}

public class BufferedReaderDemo {

/*

* 字符读取流缓冲区。

* 1、public String readLine()throws IOException读取一个文本行。

* 包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

*/

public static void main(String[] args) throws IOException {

//创建一个字符读取流对象和文件相关

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

//为了提高效率,假如缓冲技术,将字符读取流作为参数传递给缓冲区

BufferedReader bffr = new BufferedReader(fr);

String line = null;

while((line=bffr.readLine())!=null){

System.out.println(line);

}

bffr.close();

}

}

  1.  

装饰设计模式  :

 

public class zhuangshishejimoshi {

/*

* 装饰设计模式:

* 当想要对已有的对象进行功能增强时,可以定义类,将已有dx传入

* 基于已有的功能,并提供加强功能。那么自定义的该类成为装饰类。

*

* 装饰类通常会通过构造方法接受被装饰类

* 并基于被装饰类的功能。提供更强的功能。

*

* 装饰模式比继承要灵活。避免了继承体系臃肿。而且降低了类与类之间的关系。

* 装饰类因为增强了已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能。

* 所以装饰类和被装饰类通常都属于同一个体系中。

*/

public static void main(String[] args) {

Person p = new Person();

//p.chifan();

superPerson sp = new superPerson(p);

sp.superChifan();

}

}

class Person{

public void chifan(){

System.out.println("吃饭");

}

}

class superPerson{

private Person p;

superPerson(Person p){

this.p = p;

}

public void superChifan(){

System.out.println("开胃酒");

System.out.println("吃饭");

System.out.println("甜点");

System.out.println("来一根");

}

}

class MyBufferedReaderLine{

private Reader r;

public MyBufferedReaderLine(Reader r){

this.r = r;

}

public String MyreadLine(){

try {

StringBuilder sb = new StringBuilder();

char ch = 0;

while((ch = (char) r.read())!=-1){

if(ch=='\r')

continue;

else if(ch=='\n')

return sb.toString();

else

sb.append(ch);

}

} catch (IOException e) {

e.printStackTrace();

}

return null;

}

public void MyClose() throws IOException{

r.close();

}

}

  1.  

可根据装设计类模式,写出自己的BufferedReader类:

对字符类输入缓冲区还有一种形式:LineNumberReader类,他有两种方法:public int getLineNumber()获得当前行号。

和public void setLineNumber(int lineNumber)设置当前行号。其他方法和BufferedReader类中的方法基本相同,

通过这两种方法可以输入行号,设置起始行号。

   

     流操作的基本规律:

    最痛苦的就是流对象很多不知该用哪一个。

    通过两个明确来完成。

    1、明确源和目的;

          源:输入流。InputStream,Reader

          目的:输出流。OutputStream,Writer

    2、操作的数据是否是纯文本,

        是,字符流

        不是字节流 

    3、当体系明确后,在明确要使用哪个具体的对象

        通过设备来进行区分:

        源设备:内存,硬盘,键盘

        目的设备:内存,硬盘,控制台。

 

    扩展:想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。

    可以用转换流进行指定编码表的设置。

 

    IO中操作文件和文件夹的类:File

   

    字段:

public static final String separator与系统有关的默认名称分隔符

    构造方法:

    1、public File(String pathname)通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例

    2、public File(String parent, String child)根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。

    3、public File(File parent, String child)根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。

    

    普通方法:

    1、创建

            public boolean createNewFile()throws IOException在指定位置创建文件,如果该文件已经存在,则不创建返回false。

      public boolean mkdir()创建一级目录。

      public boolean mkdirs()创建多级目录。

    2、删除

            public boolean delete()删除此抽象路径名表示的文件或目录。

public void deleteOnExit()在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。

    3、判断

            public boolean exists()测试此抽象路径名表示的文件或目录是否存在

            public boolean isDirectory()测试此抽象路径名表示的文件是否是一个目录。

            public boolean isFile()测试此抽象路径名表示的文件是否是一个标准文件。

            在判断File是否是目录还是文件时,一定要先判断此File是否存在。

            public boolean isHidden()测试此抽象路径名指定的文件是否是一个隐藏文件

    4、获取信息

            public String getName()返回由此抽象路径名表示的文件或目录的名称

            public String getAbsolutePath()返回此抽象路径名的绝对路径名字符串。

            public String getPath()将此抽象路径名转换为一个路径名字符串。

            public String getParent()返回绝对路径中的父目录,获取相对路径,返回null。

如果相对路径有上一级目录,那么该目录为返回的结果.

            public long length()返回由此抽象路径名表示的文件的长度。

            

      public boolean renameTo(File dest)重新命名此抽象路径名表示的文件。

 

           文件列表:

            方法:

            public static File[] listRoots()列出可用的文件系统根

            public String[] list()返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。调用此方法的file对象必须是目录,并且该目录必须存在.

            public String[] list(FilenameFilter filter)返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。

            public File[] listFiles()返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。

            public File[] listFiles(FileFilter filter)返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录

      public File[] listFiles(FilenameFilter filter)返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录

            

        删除一个带内容的目录。

        删除原理:

        在window中,删除目录从里面往外删除。

        既然是从里往外删除,就需要用到递归。

        

 

public class FileDelete {

public static void main(String[] args) {

File f = new File("D:\\test");

deleteFile(f);

}

private static void deleteFile(File f) {

if(f.exists()){

File[] files = f.listFiles();

for (File file : files) {

if(file.isDirectory())

deleteFile(file);

else

System.out.println(file.toString()+"-files-"+file.delete());

}

System.out.println(f.toString()+"-File-"+f.delete());

}

}

}

 

        Properties是HashTable的子类。

        凡是加#号的全是注释信息,不会被Properties读取。

        也就是说它具备Map集合的特点,而且它的里面存储的键值对都是字符串。

        是集合和IO技术相结合的集合容器。

        该对象的特点:可以用于键值对形式的配置文件:

        普通方法:

        public String getProperty(String key)用指定的键在此属性列表中搜索属性。

        public Object setProperty(String key,String value)调用 Hashtable 的方法 put。使用 getProperty 方法提供并行性。强制要求为属性的键和值使用字符串

        public void list(PrintStream out)将属性列表输出到指定的输出流。

        public void list(PrintWriter out)将属性列表输出到指定的输出流。

        public void load(InputStream inStream)throws IOException从输入流中读取属性列表(键和元素对)。

        public void load(Reader reader) throws IOException按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。

        public Set<String> stringPropertyNames()返回此属性列表中的键集,其中该键及其对应值是字符串,

        public void store(OutputStream out, String comments) throws IOException以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。

 

        打印流(PrintStream,printWriter):

        该流提供了打印方法,可以将各种数据类型的数据都原样打印。

        |--PrintStrem:字节打印流

              构造函数可以接受的参数

               1、file对象。File

                2、字符串路径。String

                3、字节输出流。OutputStream

·       |--PrintWriter:字符打印流

                1、file对象。File

                2、字符串路径。String

                3、字节输出流。OutputStream

                4、字符输出流。Writer

         public PrintWriter(OutputStream out,boolean autoFlush)通过现有的 OutputStream 创建新的 PrintWriter。

        autoFlush - boolean 变量;如果为 true,则 println、printf 或 format 方法将刷新输出缓冲区

 

 

            SequenceInputStream:多个流集合成一个流。再进行数据传送。

            构造方法:

            public SequenceInputStream(InputStream s1,InputStream s2)通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。

            public SequenceInputStream(Enumeration<? extends InputStream> e)通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。将按顺序读取由该枚举生成的输入流,以提供从此SequenceInputStream 读取的字节。在用尽枚举中的每个输入流之后,将通过调用该流的 close 方法将其关闭。         

 

//合并文件

public static void merge() throws IOException{

ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();

for(int i =1;i<=2;i++){

al.add(new FileInputStream(i+".part"));

}

final Iterator<FileInputStream> it = al.iterator();

Enumeration<FileInputStream> en = new Enumeration<FileInputStream>(){

@Override

public boolean hasMoreElements() {

return it.hasNext();

}

@Override

public FileInputStream nextElement() {

return it.next();

}

};

SequenceInputStream sis = new SequenceInputStream(en);

FileOutputStream fos = new FileOutputStream("whole.txt");

byte[] buf = new byte[1024];

int len = 0;

while((len=sis.read(buf))!=-1){

fos.write(buf, 0, len);

}

sis.close();

fos.close();

}

            文件分割:            

 

public static void splitFile() throws IOException{

FileInputStream fis = new FileInputStream("demo3.txt");

FileOutputStream fos = null;

byte[] buf = new byte[1024];

int len  = 0;

int count = 1;

while((len=fis.read(buf))!=-1){

fos = new FileOutputStream((count++)+".part");

fos.write(buf, 0, len);

fos.close();

}

fis.close();

}

            

        对象的序列化:

        能操作对象的流:ObjectInputStream,ObjectOutputStream

        |--ObjectOutputStream

            构造方法:

            public ObjectOutputStream(OutputStream out)throws IOException创建写入指定 OutputStream 的 ObjectOutputStream。此构造方法将序列化流部分写入底层流

            普通方法:

            public final void writeObject(Object obj)throws IOException将指定的对象写入 ObjectOutputStream。( NotSerializableException - 某个要序列化的对象不能实现 java.io.Serializable 接口。)

         |--ObjectInputStream

            构造方法:

            public ObjectInputStream(InputStream in)throws IOException创建从指定 InputStream 读取的 ObjectInputStream。从流读取序列化头部并予以验证。

            普通方法:

            public final Object readObject()throws IOExceptionClassNotFoundException从 ObjectInputStream 读取对象

            对象的标识:public static final long serialVersionUID = 42L;这个变量可以系统生成也可以自己定义。

            静态是不能被序列化。

            如果不是静态的也不想被序列化可以用关键字:transient修饰。

 

        管道流:这个和线程有关,学完线程后再看看。

        输入输出可以直接进行链接,通过线程结合使用。

        |--PipedInputStream

            构造方法:

            public PipedInputStream(PipedOutputStream src)throws IOException创建 PipedInputStream,使其连接到管道输出流 src。写入 src 的数据字节可用作此流的输入。

            普通方法:            

      public void connect(PipedOutputStream src)throws IOException使此管道输入流连接到管道输出流 src。

        |--PipedOutputStream

            构造方法:

            public PipedOutputStream(PipedInputStream snk)throws IOException创建连接到指定管道输入流的管道输出流。写入此流的数据字节稍后将用作 snk 的输入。

            普通方法:

            public void connect(PipedInputStream snk)throws IOException将此管道输出流连接到接收者。

 

            RandomAccessFile:

            随机访问文件,自身具备读写的方法。

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

 

/*

* RandomAccessFile类

* 该类不算是IO体系中的子类

* 而是直接继承Object。

*

* 但是它是IO包中的成员。因为它具备读和写的功能。

* 内部封装了一个数组,而且通过指针对数组的元素的进行操作。

* 可以通过getFilePointer获取指针位置

* 同时可以通过seek改变指针的位置。

*

* 其实完成读写的原理就是内部封装了字节输入和输出流。

*

* 通过构造函数可以看出,该类只能操作文件。

* 而且操作文件还有模式:只读 r,读写 rw等。

*

* 如果模式为只读 r,不会创建文件。会读取一个已存在的文件。如果文件不存在,则会报出异常。

* 如果模式是读写 rw,要操作的文件不存在,会自动创建。如果存在则不会覆盖。

*/

public class RandomAccessFileDemo {

public static void main(String[] args) throws IOException {

//writeFile();

//readFile();

writeFile_2();

}

public static void readFile() throws IOException{

RandomAccessFile raf = new RandomAccessFile("ran.txt","r");

//调整读写中的指针

//raf.seek(8);

//跳过指定的字节数,这个方法不能往回走。

raf.skipBytes(8);

byte[] buf = new byte[4];

raf.read(buf);

String name = new String(buf);

System.out.println("name="+name);

int age = raf.readInt();

System.out.println("Age="+age);

raf.close();

}

public static void writeFile_2() throws IOException{

RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");

raf.seek(8*3);

raf.write("周七".getBytes());

raf.writeInt(103);

raf.close();

}

public static void writeFile() throws IOException{

RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");

raf.write("李四".getBytes());

raf.writeInt(97);

raf.write("王五".getBytes());

raf.writeInt(99);

raf.close();

}

}

 

                操作基本数据类型:

                |--DataInputStream

                |--DateOutputStream

 

/*

* DataInputStream和DataOutputStream

*

* 可以用于操作基本数据类型的数据对象。

*

* 构造函数:

* DataInputStream(InputStream is);

* DataOutputStream(OutputStream os);

*

* 比较特殊的方法:

* writeUTF(String str) 以与机器无关方式使用UTF-8修改版编码将一个字符串写入基础输出流

*/

public class DateStreamDemo {

public static void main(String[] args) throws IOException {

writeUTFDemo();

}

public static void writeUTFDemo() throws IOException{

DataOutputStream dos = new DataOutputStream(new FileOutputStream("Date.txt"));

dos.writeUTF("你好");

dos.close();

}

public static void rw() throws IOException{

DataOutputStream dos = new DataOutputStream(new FileOutputStream("Date.txt"));

dos.writeInt(234);

dos.writeBoolean(true);

dos.writeDouble(9887.543);

dos.close();

DataInputStream dis = new DataInputStream(new FileInputStream("Date.txt"));

int i = dis.readInt();

boolean b = dis.readBoolean();

double d = dis.readDouble();

System.out.println(i+" "+d+" "+b);

dis.close();

}

}

            

            操作数组的IO流

            ByteArrayInputStream,ByteArrayOutputStream:关闭这两个流的无效的,而且不会产生任何IO异常。

            操作字符数组的IO流

            CharArrayReader,CharArrayWriter

            操作字符串的IO流

            StringReader,StringWriter

            三类流的操作等,基本相同,详见API

posted @ 2018-03-05 17:31  聆听*幸福  阅读(136)  评论(0编辑  收藏  举报