您的位置:首页 > 职场人生

黑马程序员,Java基础知识八:IO流

2014-12-31 10:14 381 查看

IO流

IO流用来处理设备之间的数据传输,Java对数据的操作都是通过流的方式,而操作流的对象都在IO包中。

流按操作数据分为两种:字符流和字节流,按流向分为输入流和输出流。

字节流的抽象基类:InputStream,OutputStream。

字符流的抽象基类:Reader,Writer。

注意:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。如:InputStream的子类FileInputStream。Reader的子类FileReader。

字符流

创建文件,写入文件:

1,创建流对象,建立数据存放文件。

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

2,调用流对象的写入方法,将数据写入流
fw.write("text");

3,关闭流资源,并将流中的数据清空到文件中。
fw.close();

完整的代码示例:
FileWriter fw = null;
try{
fw = new FileWriter("text.txt");
fw.write("text");
}
catch(IOException e){
System.out.println(e.toString());
}
finally{
if(fw!=null)
try{
fw.close();
}
catch(IOException e){
System.out.println(e.toString());
}
}

读取文件

1,建立流对象,将已存在的一个文件加载进流。

FileReader fr = new FileReader("Test.txt")

2,创建一个临时存放数据的数组。
char[] ch = new char[1024];

3,调用流对象的读取方法将流中的数据读入到数组中。
fr.read(ch);

完整的代码示例:
import java.io.*;

class FileReaderDemo
{
public static void main(String[] args) throws IOException
{
//创建一个文件读取流对象,和指定名称的文件相关联。
//要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException
FileReader fr = new FileReader("demo.txt");

//调用读取流对象的read方法。
//read():一次读一个字符。而且会自动往下读。

int ch = 0;

while((ch=fr.read())!=-1)
{
System.out.println(
}

/*
while(true)
{
int ch = fr.read();
if(ch==-1)
break;
System.out.println("ch="+(char)ch);
}
*/

fr.close();

}
}

注意:

1,在定义文件路径时,可以用“/”或者“\\”。

2,在创建一个文件时,如果目录下有同名文件将被覆盖。

3,在读取文件时,必须保证该文件已经存在,否则出异常。

字符流缓冲区

缓冲区的出现提高了对数据的读写效率。对应的类有BufferWriter和BufferReader。缓冲区必须要结合流才可以使用,它在流的基础上对流的功能进行了增强。

字符流缓冲区提供了一次读一行的方法 readLine,方便于对文本数据的获取。

当返回null时,表示读到文件末尾。readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。import java.io.*;

class BufferedReaderDemo
{
public static void main(String[] args) throws IOException
{
//创建一个读取流对象和文件相关联。
FileReader fr = new FileReader("buf.txt");

//为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。
BufferedReader bufr = new BufferedReader(fr);

String line = null;

while((line=bufr.readLine())!=null)
{
System.out.print(line);
}

bufr.close();
}

}

字节流

字节流的基本操作和字符流相同,但它不仅可以操作字符,还可以操作其他媒体文件。类似于字符流,它有InputStream和OutputStream

import java.io.*;
class FileStream
{
public static void main(String[] args) throws IOException
{
readFile_3();
}

public static void readFile_3()throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");

// int num = fis.available();
byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区。不用在循环了。

fis.read(buf);

System.out.println(new String(buf));

fis.close();
}

public static void readFile_2()throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");

byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1)
{
System.out.println(new String(buf,0,len));
}

fis.close();

}

public static void readFile_1()throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");

int ch = 0;

while((ch=fis.read())!=-1)
{
System.out.println((char)ch);
}

fis.close();
}

public static void writeFile()throws IOException
{
FileOutputStream fos = new FileOutputStream("fos.txt");

fos.write("abcde".getBytes());

fos.close();

}
}

字节流缓冲区

同字符流缓冲区,它也是提高了字节流的读写效率。

import java.io.*;

class MyBufferedInputStream
{
private InputStream in;

private byte[] buf = new byte[1024*4];

private int pos = 0,count = 0;

MyBufferedInputStream(InputStream in)
{
this.in = in;
}

//一次读一个字节,从缓冲区(字节数组)获取。
public int myRead()throws IOException
{
//通过in对象读取硬盘上数据,并存储buf中。
if(count==0)
{
count = in.read(buf);
if(count<0)
return -1;
pos = 0;
byte b = buf[pos];

count--;
pos++;
return b&255;
}
else if(count>0)
{
byte b = buf[pos];

count--;
pos++;
return b&0xff;
}
return -1;

}
public void myClose()throws IOException
{
in.close();
}
}

转换流

转换流是字符流和字节流之间的桥梁,它方便了字节流和字符流之间的操作。当字节流中的数据都是字符时,可以转成字符流进行操作更加高效。import java.io.*;

class TransStreamDemo
{
public static void main(String[] args) throws IOException
{
//获取键盘录入对象。
//InputStream in = System.in;
//将字节流对象转成字符流对象,使用转换流。InputStreamReader
//InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
//BufferedReader bufr = new BufferedReader(isr);
//键盘的最常见写法。
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}

bufr.close();

}
}

流操作的基本规律

最痛苦的就是流对象有很多,而我们不知道该用哪一个。

    通过两个明确来完成:

1、明确源和目的

源:输入流InputStream , Reader

目的:输出流OutputStream , Writer

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

是:字符流。

否:字节流。

3.当体系明确后,再明确要使用哪个具体的对象。

通过设备来进行区分:

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

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

这三个分别对应(ArrayStream,FileStream,System)

通常我们在设计到字符编码转换时,需要用转换流

另外转换流可以直接与流关联:键盘,控制台。

但不能直接与文件相关联,它与文件之间还需要加一个操作文件的流对象(FileInputStream,FileOutputStream或者FileReader,FileWriter)
class TransStreamDemo2
{
public static void main(String[] args) throws IOException
{
System.setIn(new FileInputStream("PersonDemo.java"));

System.setOut(new PrintStream("zzz.txt"));

//键盘的最常见写法。
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

String line = null;

while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}

bufr.close();

}
}

标准输入输出流

在System类中有in和out流对象,他们代表了系统标准的输入和输出设备。默认输入设备是键盘,输出设备是显示器。

System.in的类型是InputStream, System.out的类型是PrintStream,它是OutputStream子类FileOutputStream的子类

键盘录入:

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

控制台输出:
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

流操作小结:

流是用来处理数据的,处理数据时,一定要明确数据源和数据目的地(数据汇)。

数据源可以是文件,也可以是键盘。

数据目的地可以是文件、显示器或者其他设备。

而流只是在帮助数据进行传输,并对传输的数据进行处理,比如过滤处理、转换处理等。

File类

用来将文件或者文件夹封装成对象。它方便对文件和文件夹的属性信息进行操作。

File对象也可以作为参数传递给流的构造函数。

File类常见方法:

1,创建。

    boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。

    boolean mkdir():创建文件夹。

    boolean mkdirs():创建多级文件夹。

2,删除。

    boolean delete():删除失败返回false。如果文件正在被使用,则删除不了返回falsel。

    void deleteOnExit();在程序退出时删除指定文件。

3,判断。

    boolean exists() :文件是否存在.

    isFile():

    isDirectory();

    isHidden();

    isAbsolute();

4,获取信息。

    getName():

    getPath():

    getParent():

    getAbsolutePath()

    long lastModified()

    long length()
class FileDemo
{
public static void main(String[] args) throws IOException
{
method_5();
}

public static void method_5()
{
File f1 = new File("c:\\Test.java");
File f2 = new File("d:\\hahah.java");

sop("rename:"+f2.renameTo(f1));

}

public static void method_4()
{
File f = new File("file.txt");

sop("path:"+f.getPath());
sop("abspath:"+f.getAbsolutePath());
sop("parent:"+f.getParent());//该方法返回的是绝对路径中的父目录。如果获取的是相对路径,返回null。
//如果相对路径中有上一层目录那么该目录就是返回结果。

}

public static void method_3()throws IOException
{
File f = new File("d:\\java1223\\day20\\file2.txt");

//f.createNewFile();

//f.mkdir();

//记住在判断文件对象是否是文件或者目的时,必须要先判断该文件对象封装的内容是否存在。
//通过exists判断。
sop("dir:"+f.isDirectory());
sop("file:"+f.isFile());

sop(f.isAbsolute());
}

public static void method_2()
{
File f = new File("file.txt");

//sop("exists:"+f.exists());

//sop("execute:"+f.canExecute());

//创建文件夹
File dir = new File("abc\\kkk\\a\\a\\dd\\ee\\qq\\aaa");

sop("mkdir:"+dir.mkdirs());
}

public static void method_1()throws IOException
{
File f = new File("file.txt");
// sop("create:"+f.createNewFile());
//sop("delete:"+f.delete());

}

//创建File对象
public static void consMethod()
{
//将a.txt封装成file对象。可以将已有的和为出现的文件或者文件夹封装成对象。
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");

sop("f1:"+f1);
sop("f2:"+f2);
sop("f3:"+f3);

File f4 = new File("c:"+File.separator+"abc"+File.separator+"zzz"+File.separator+"a.txt");

}

public static void sop(Object obj)
{
System.out.println(obj);
}
}

IO包中的其他类


RandomAccessFile

RandomAccessFile可以随机的访问文件,自身具备读写的方法。该类不能算是IO体系中的子类,因为它直接继承自Object,但它也是IO包中的成员,因为它具备读和写的功能。内部封装了一个数组,而且通过指针对数组的元素进行操作。可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置。通过skipBytes(int x)和seek(int x)来达到随机访问的效果。其实完成读写的原理就是内部封装了字节输入流和输出流。

该类只能操作文件,而且操作文件有几种模式可选:只读r,读写rw等。如果模式为只读 r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。如果模式rw。操作的文件不存在,会自动创建。如果存则不会覆盖。

class RandomAccessFileDemo
{
public static void main(String[] args) throws IOException
{
//writeFile_2();
//readFile();

//System.out.println(Integer.toBinaryString(258));

}

public static void readFile()throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.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_2()throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.seek(8*0);
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();
}
}

管道流

pipedInputStream和pipedOutputStream,他们就像形同了管道,让输入输出连接起来,可以结合线程来使用。

import java.io.*;

class Read implements Runnable
{
private PipedInputStream in;
Read(PipedInputStream in)
{
this.in = in;
}
public void run()
{
try
{
byte[] buf = new byte[1024];

System.out.println("读取前。。没有数据阻塞");
int len = in.read(buf);
System.out.println("读到数据。。阻塞结束");

String s= new String(buf,0,len);

System.out.println(s);

in.close();

}
catch (IOException e)
{
throw new RuntimeException("管道读取流失败");
}
}
}

class Write implements Runnable
{
private PipedOutputStream out;
Write(PipedOutputStream out)
{
this.out = out;
}
public void run()
{
try
{
System.out.println("开始写入数据,等待6秒后。");
Thread.sleep(6000);
out.write("piped lai la".getBytes());
out.close();
}
catch (Exception e)
{
throw new RuntimeException("管道输出流失败");
}
}
}

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

PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out);

Read r = new Read(in);
Write w = new Write(out);
new Thread(r).start();
new Thread(w).start();

}
}

打印流

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

字节打印流:PrintStream,构造函数可以接收的参数类型:1,file对象。File,2,字符串路径。String,3,字节输出流。OutputStream

字符打印流:PrintWriter,构造函数可以接收的参数类型:1,file对象。File,2,字符串路径。String,3,字节输出流。OutputStream,4,字符输出流,Writer。

import java.io.*;

class  PrintStreamDemo
{
public static void main(String[] args) throws IOException
{
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));

PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true);

String line = null;

while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
out.println(line.toUpperCase());
//out.flush();
}

out.close();
bufr.close();

}
}

序列流

SequenceInputstream,和SequenceOutputStream使用序列流可以将多个流合并。

import java.io.*;

class Read implements Runnable
{
private PipedInputStream in;
Read(PipedInputStream in)
{
this.in = in;
}
public void run()
{
try
{
byte[] buf = new byte[1024];

System.out.println("读取前。。没有数据阻塞");
int len = in.read(buf);
System.out.println("读到数据。。阻塞结束");

String s= new String(buf,0,len);

System.out.println(s);

in.close();

}
catch (IOException e)
{
throw new RuntimeException("管道读取流失败");
}
}
}

class Write implements Runnable
{
private PipedOutputStream out;
Write(PipedOutputStream out)
{
this.out = out;
}
public void run()
{
try
{
System.out.println("开始写入数据,等待6秒后。");
Thread.sleep(6000);
out.write("piped lai la".getBytes());
out.close();
}
catch (Exception e)
{
throw new RuntimeException("管道输出流失败");
}
}
}

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

PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out);

Read r = new Read(in);
Write w = new Write(out);
new Thread(r).start();
new Thread(w).start();

}
}

操作对象

ObjectInputStream和ObjectOutputStream,被操作的对象需要实现Serializable(标记接口)。

操作基本数据类型

DataInputStream和DataOutputStream可以用于操作基本数据类型的数据的流对象。

操作字节数组

用于操作字节数组的流对象。

ByteArrayInputStream :  在构造的时候,需要接收数据源,而且数据源是一个字节数组。

ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。也就是数据的目的地。

注意:因为这两个流对象都操作的数组,并没有使用系统资源。所以不用进行close关闭。

操作字符数组

CharArrayReader与CharArrayWrite

操作字符串

StringReader与StringWriter

字符编码

字符流的出现是为了方便操作字符,而且更重要的是它加入了编码转换。

通过子类转换流来完成:inputStreamReader和OutputStreamWriter。

在两个对象进行构造的时候可以加入字符集。

它可以让字符以指定编码格式进行存储。

可以让文本数据以指定编码格式来解读。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 笔记 io流