字节流
抽象基类:InputStream OutputStream
1、 字节输入流
InputStream也是一个抽象类,从流中得到的为字节
常用方法:
abstract int read()throws IOException从流中得到一个字节,用int表示,如果为-1表示到文件末尾。
int read(byte[]b) throws IOException得到多个字节,放入数组b中,返回实际得到的字节数,-1表示到流的末尾。
void close() throws IOException关闭流。
从流中得到一个字节进行输入的大致步骤
1、 创建一个字节流对象,指明从哪里输入
2、 int b = 0;//存储从流中得到的一个字节的内容
while(true){
b=in.read();//得到内容并判断流是否结束
if(b==-1)break;
处理流中得到的字节
}
In.close();//关闭流
简化形式:
While((b=in.read())!=-1)
{
处理得到的字节b
}
In.close();
从流中得到多个字节进行输入的大致步骤
1、创建一个字节流对象,指明从哪里输入
2、int len =0;//存储从流中得到的字节数
byte[] b = new byte[1024];//存储从流中得到的一个字节的内容
while(true){
len=in.read(b);//得到内容并判断流是否结束
if(len==-1)break;
处理流中得到的字节
}
In.close();//关闭流
简化形式:
While((len=in.read(b))!=-1){
处理得到的字节b
}
in.close();
常用子类:FileinputStream BufferedInputStream]
FileInputStream有两个构造方法:
FileInputStream(String name) FileInputStream(File file)
文件读取流实例:
package IOTest;
import java.io.*;
public class FileInputStreamDemo {
public static void main(String[] args)throws IOException {
// TODO Auto-generated method stub
FileInputStreamDemo demo = new FileInputStreamDemo();
demo.readFile("FileInputStreamDemo.java");
}
public void readFile(String fileName)throws IOException
{
InputStream in = null;
try{
in = new FileInputStream(fileName);//指明从哪里输入
int len = 0;
byte[] b = new byte[1024];
while((len=in.read(b))!=-1)//得到内容并判断是否为空
{
System.out.println(new String(b,0,len));
}
}finally
{
if(in !=null)
in.close();//关闭流
}
}
}
BufferedInputStream 是一个缓冲字节流,可以套接在其他流上进行功能的增强。
BufferedInputStream使用实例:
package IOTest;
import java.io.*;
public class BufferedInputStreamDemo {
public static void main(String[] args) throws IOException{
BufferedInputStreamDemo demo = new BufferedInputStreamDemo();
demo.readFile("BufferedInputStreamDemo.java");
}
private void readFile(String fileName) throws IOException
{
InputStream in = null;
try{
in = new BufferedInputStream(new FileInputStream(fileName));//指明从哪里输入
int len = 0;
byte[] b = new byte[1024];
while((len=in.read(b))!=-1)//得到内容并判断是否为空
{
System.out.println(new String(b,0,len));
}
}finally
{
if(in !=null)
in.close();//关闭流
}
}
}
拷贝一个图片的简单实现:
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("1.jpg"));
BufferedOutputStreambufos = new BufferedOutputStream(new FileOutptStream("2.jpg"));
int by = 0;
while((by=bufis.read())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.close();
字节流的read()方法读取一个字节。为什么返回的不是byte类型,而是int类型呢?
因为read方法读到末尾时返回的是-1.
而在所操作的数据中的很容易出现连续多个1的情况,而连续读到8个1,就是-1.
导致读取会提前停止。
所以将读到的一个字节给提升为一个int类型的数值,但是只保留原字节,并在剩余二进制位补0.
具体操作是:byte&255 or byte&0xff
对于write方法,可以一次写入一个字节,但接收的是一个int类型数值。
只写入该int类型的数值的最低一个字节(8位)。
简单说:read方法对读到的数据进行提升。write对操作的数据进行转换。
转换流:
特点:
1,是字节流和字符流之间的桥梁。
2,该流对象中可以对读取到的字节数据进行指定编码表的编码转换。
什么时候使用呢?
1,当字节和字符之间有转换动作时。
2,流操作的数据需要进行编码表的指定时。
具体的对象体现:
1,InputStreamReader:字节到字符的桥梁。
2,OutputStreamWriter:字符到字节的桥梁。
构造函数:
InputStreamReader(InputStream):通过该构造函数初始化,使用的是本系统默认的编码表GBK。
InputStreamReader(InputStream,StringcharSet):通过该构造函数初始化,可以指定编码表。
OutputStreamWriter(OutputStream):通过该构造函数初始化,使用的是本系统默认的编码表GBK。
OutputStreamWriter(OutputStream,StringcharSet):通过该构造函数初始化,可以指定编码表。
操作文件的字符流对象是转换流的子类。
Reader
|--InputStreamReader
|--FileReader
Writer
|--OutputStreamWriter
|--FileWriter
转换流中的read方法。已经融入了编码表,
在底层调用字节流的read方法时将获取的一个或者多个字节数据进行临时存储,
并去查指定的编码表,如果编码表没有指定,
查的是默认码表。那么转流的read方法就可以返回一个字符比如中文。
转换流已经完成了编码转换的动作,对于直接操作的文本文件的FileReaer而言,就不用在重新定义了,
只要继承该转换流,获取其方法,就可以直接操作文本文件中的字符数据了。
注意:
在使用FileReader操作文本数据时,该对象使用的是默认的编码表。
如果要使用指定编码表时,必须使用转换流。
FileReader fr = newFileReader("a.txt");//操作a.txt的中的数据使用的本系统默认的GBK。
操作a.txt中的数据使用的也是本系统默认的GBK。
InputStreamReader isr = new InputStreamReader(newFileInputStream("a.txt"));
这两句的代码的意义相同。
如果a.txt中的文件中的字符数据是通过utf-8的形式编码。
那么在读取时,就必须指定编码表。
那么转换流必须使用。
InputStreamReader isr = new InputStreamReader(newFileInputStream("a.txt"),"utf-8");
流操作的基本规律。
1,明确数据源和数据汇(数据目的)。
其实是为了明确输入流还是输出流。
2,明确操作的数据是否是纯文本数据。
其实是为了明确字符流还是字节流。
数据源:键盘System.in,硬盘File开头的流对象,内存(数组)。
数据汇:控制台System.out,硬盘File开头的流对象,内存(数组)。
需求:
1,将键盘录入的数据存储到一个文件中。
数据源:System.in
既然是源,使用的就是输入流,可用的体系有InputStream,Reader。
因为键盘录入进来的一定是纯文本数据,所以可以使用专门操作字符数据的Reader。
发现System.in对应的流是字节读取流。所以要将其进行转换,将字节转成字符即可。
所以要使用Reader体系中:InputStreamReader
接下来,是否需要提高效率呢?如果需要,那么就加入字符流的缓冲区:BufferedReader
BufferedReaderbur = new BufferedReader(new InputStreamReader(System.in));
数据汇:一个文件,硬盘。
既然是数据汇,那么一定是输出流,可以用的OutputStream,Writer。
往文件中存储的都是文本数据,那么可以使用字符流较为方便:Writer
因为操作的是一个文件。所以使用Writer中的FileWriter。
是否要提高效率呢?是,那就使用BufferedWriter.
BufferedWriter bufr= new BufferedWriter(new FileWriter("a.txt"));
附加需求:希望将这些文本数据按照指定的编码表存入文件中。
既然是文本数据,而是还是写入到文件中,那么使用的体系还是Writer。
因为要指定编码表,所以要使用Writer中的转换流,OutputStreamWriter。
是否要提高效率,是,选择BufferedWriter。
注意:虽然是最终是文件,但是不可以选择FileWriter。因为该对象是使用默认编码表。
输出转换流要接收一个字节输出流进来,所以要是用OutputStram体系,而最终输出到一个文件中,
那么就要使用OutputStream体系中可以操作的文件的字节流对象:FileOutputStream。
//StringcharSet = System.getProperty("file.encoding");
StringcharSet = "utf-8";
BufferedWriterbufw = new BufferedWriter(new OutputStreamWriter(newFileOutputStream("a.txt"),charSet);
代码:
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt")));
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
}
}
2、将一个文件显示在控制台上:
public static void readText_2() throws IOException, FileNotFoundException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk_1.txt"),"utf-8");
char[] buf = new char[10];
int len = isr.read(buf);
String str = new String(buf,0,len);
System.out.println(str);
isr.close();
}
File类:
该类的出现是对文件系统的中的文件以及文件夹进行对象的封装。
可以通过对象的思想来操作文件以及文件夹。
1,构造函数:
File(String filename):将一个字符串路径(相对或者绝对)封装成File对象,该路径是可存在的,也可以是不存在。
File(String parent,String child);
File(Fileparent,String child);
2,特别的字段:separator:跨平台的目录分隔符。
例子:File file = newFile("c:"+File.separator+"abc"+File.separator+"a.txt");
3,常见方法:
1,创建:
boolean createNewFile()throws IOException:创建文件,如果被创建的文件已经存在,则不创建。
boolean mkdir():创建文件夹。
boolean mkdirs(): 创建多级文件夹。
2,删除:
boolean delete():可用于删除文件或者文件夹。
注意:对于文件夹只能删除不带内容的空文件夹,
对于带有内容的文件夹,不可以直接删除,必须要从里往外删除。
void deleteOnExit(): 删除动作交给系统完成。无论是否反生异常,系统在退出时执行删除动作。
3,判断:
boolean canExecute():
boolean canWrite():
boolean canRead();
boolean exists():判断文件或者文件夹是否存在。
boolean isFile(): 判断File对象中封装的是否是文件。
boolean isDirectory():判断File对象中封装的是否是文件夹。
boolean isHidden():判断文件或者文件夹是否隐藏。在获取硬盘文件或者文件夹时,
对于系统目录中的文件,java是无法访问的,所以在遍历,可以避免遍历隐藏文件。
4,获取:
getName():获取文件或者文件夹的名称。
getPath():File对象中封装的路径是什么,获取的就是什么。
getAbsolutePath():无论File对象中封装的路径是什么,获取的都是绝对路径。
getParent(): 获取File对象封装文件或者文件夹的父目录。
注意:如果封装的是相对路径,那么返回的是null.
long length():获取文件大小。
longlastModified():获取文件或者文件最后一次修改的时间。
static File[] listRoots():获取的是被系统中有效的盘符。
String[] list():获取指定目录下当前的文件以及文件夹名称。
String[] list(Filenamefilter): 可以根据指定的过滤器,过滤后的文件及文件夹名称。
File[] listFiles():获取指定目录下的文件以及文件夹对象。
5,重命名:
renameTo(File):
File f1 = newFile("c:\\a.txt");
File f2 = newFile("c:\\b.txt");
f1.renameTo(f2);//将c盘下的a.txt文件改名为b.txt文件。
递归:
其实就是在使用一个功能过程中,又对该功能有需求。
就出现了函数自身调用自身。
注意:
1,一定要限定条件,否则内存溢出。
2,使用递归时,调用次数不要过多,否则也会出现内存溢出。
需求:
1、想要列出指定目录下的文件以及文件夹中的文件(子文件)。
import java.io.*;
public class FileExtFilter implements FilenameFilter{
private String ext;
FileExtFilter(String ext)
{
this.ext = ext;
}
public boolean accept(File dir, String name) {
if(new File(dir,name).isDirectory())
return false;
if(name.endsWith(ext))
return true;
return false;
}
}
public class FileFilter implements FilenameFilter{
private String ext;
FileFilter(String ext)
{
this.ext = ext;
}
@Override
public boolean accept(File dir, String name) {
// TODO Auto-generated method stub
if(new File(dir,name).isDirectory())
return false;
if(name.endsWith(ext))
return true;
return false;
}
}
2,需求:删除一个带内容的目录。
原理:从里往外删除,所以需要使用递归完成。
public void deleteAll(File dir)
{
File[] files = dir.listFiles();
for(int x=0; x<files.length; x++)
{
if(files[x].isDirectory())
deleteAll(files[x]);
else
files[x].delete();
}
dir.delete();
}