------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
IO流(字节流File读写操作)
操作字节流的方法和操作字符流的方法大部分是相同的
字节流的两个基类:InputStream(读取流)OutputStream(写入流)
代码演示:
<pre name="code" class="java">import java.io.*;
class Lianxi
{
public static void main(String[] args)throws IOException
{
readFile_2();
}
public static void readFile_2()throws IOException
{
FileInputStream fis = new FileInputStream("G:\\fos.txt");
/*
intnum = fis.available();
System.out.println("num:"+num);//发现输出结果为5(字符的个数)有什么用呢?
//分析发现:available方法可以定义一个刚刚好缓冲区。不用再循环了。
//但是此方法也要慎用,因为一旦文件太大,就会发生内存溢出。
*/
byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区。
fis.read(buf);
System.out.println(new String(buf));
fis.close();
}
//此方法将读到的数据,先存到一个byte数组里面,最后再打印。效率稍高
public static void readFile_1()throws IOException
{
FileInputStream fis = new FileInputStream("G:\\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()throws IOException
{
FileInputStream fis = new FileInputStream("G:\\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("G:\\fos.txt");
fos.write("abcde".getBytes());
fos.close();
}
}
演示从C盘复制一张图片数据到G盘。这时就要用到字节流。
代码演示:
/*
思路:
1字节读取流对象和一张图片相关联
2用字节写入流对象创建一个图片文件。用于存储获取到的图片数据。
3通过循环读写完成数据的存储
4关闭资源。
*/
import java.io.*;
class Lianxi
{
public static void main(String[]args)
{
FileOutputStream fos = null;
FileInputStream fis = null;
try
{
fos= new FileOutputStream("g:\\yanshi_copy.png");
fis= new FileInputStream("c:\\yanshi.png");
//byte[] buf = new byte[fis.available()];
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
}
catch(IOException e)
{
throw new RuntimeException("复制文件失败");
}
finally
{
try
{
if(fis!=null)
fis.close();
}
catch(IOException e)
{
new RuntimeException("读取关闭失败");
}
try
{
if(fos!=null)
fos.close();
}
catch(IOException e)
{
new RuntimeException("写入关闭失败");
}
}
}
}
演示MP3的复制,通过缓冲区
代码演示:
import java.io.*;
class Lianxi
{
public static void main(String[]args)throws IOException
{
copy_1();
}
public static void copy_1()throws IOException
{
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\yanshi.jpg"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("g:\\yanshi1.jpg"));
int by = 0;
while((by=bufis.read())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.close();
}
}
读取键盘录入
代码演示:
import java.io.*;
class Yanshi
{
public static void main(String[]args)throws IOException
{
InputStream in = System.in;
StringBuilder sb = new StringBuilder();
while(true)
{
int ch = in.read();
if(ch=='\r')
continue;
if(ch=='\n')
{
String s = sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
sb.delete(0,sb.length());
}
else
sb.append((char)ch);
}
}
}
通过以上代码演示发现,其实就是读一行数据的原理
也就是readerLine方法。
能不能直接使用readerLine方法来完成键盘录入的一行数据的读取呢?
InputStreamReader(读取转换流)
它是字节流同享字符流的桥梁。
代码演示:
import java.io.*;
class Lianxi
{
public static void main(String[]args)throws IOException
{
//获取键盘录入对象
InputStream in = System.in;
//将字节流对象转成字符流对象,使用转换流InputStreamReader()
InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,将字符流进行缓冲技术高效操作,使用BufferedReader
BufferedReader bufr = new BufferedReader(isr);
String line = null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
System.out.println(line.toUpperCase());
}
bufr.close();
}
}
写入流转换(OutputStreamWriter)
它是字符流通向字节流的桥梁。
代码演示:
import java.io.*;
class Lianxi
{
public static void main(String[]args)throws IOException
{
//获取键盘录入对象
//InputStream in = System.in;
//将字节流对象转成字符流对象,使用转换流InputStreamReader()
//InputStreamReader isr = newInputStreamReader(in);
//为了提高效率,将字符流进行缓冲技术高效操作,使用BufferedReader
//BufferedReader bufr = new BufferedReader(isr);
//键盘录入的最常见写法 (也可以理解为数据的源)
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
//OutputStream out = System.out;
//OutputStreamWriter osw = newOutputStreamWriter(out);
//BufferedWriter bufw = new BufferedWriter(osw);
//可以理解为数据输出的目的地控制台
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当体系明确后,再明确要使用哪个具体的对象。
通过设备来进行区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台。
import java.io.*;
class Lianxi
{
public static void main(String[]args)throws IOException
{
//演示:将一个文件的数据打印在控制台上
//源是文件,目的是控制台。
BufferedReader bufr =
new BufferedReader(new InputStreamReader(new FileInputStream("g:\\person.java")));
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();
/*
//演示:把键盘录入的数据存储到一个文件中
//键盘录入的最常见写法
BufferedReader bufr =
newBufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw =
newBufferedWriter(new OutputStreamWriter(new FileOutputStream("g:\\out.txt")));
Stringline = null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
*/
}
}
File类
用来将文件或者文件夹封装成对象的类
方便对文件与文件夹的属性进行操作
File对象可以作为参数传递给流的构造函数
它也弥补了流的不足(因为流只可以操作数据)
File类的常见方法:
1创建。
boolean createNewFile();在指定位置创建文件,如果该文件存在就不创建,返回false和输出流不一样,输出流对象一建立创建文件,而且文件存在的话会覆盖。
boolean mkdir();创建文件夹。
Boolean mkdirs();创建多级文件夹。
2删除。
boolean delete();删除失败返回false。
void deleteOnExit();在程序退出时,删除指定文件。
3判断。
boolean exists();文件是否存在。
boolean canExecute();文件是否可运行
boolean isFile();是否是文件
boolean isDirectory();是否是目录
boolean isHidden(); 是否是隐藏文件
boolean isAbsoute();是否是绝对路径。
4获取信息。
String getName();获取名称。
String getPath();获取路径。
String getParent();获取绝对路径中的父目录。如果是获取相对路径,返回null
如果相对路径中,有上一层目录,那么该目录就是返回的结果。
String getAbsolutePath();获取绝对路径。
Long lastModified();返回文件最后被修改的时间。
Long length(); 返回文件的大小。
File[] listFiles();返回一个抽象路径名数组
递归
代码演示:
//列出指定目录下文件或者文件夹,包含子目录中的内容。(这时就要用到递归)
//也就是函数自身调用自身。
//这种表现形式,或者编程手法称为递归
//也就是列出指定目录下所有的内容
import java.io.*;
class Yanshi
{
public static void main(String[]args)
{
File dir = new File("g:\\Injava");
showDir(dir);
}
public static void showDir(File dir)
{
System.out.println(dir);
File[]files = dir.listFiles();
for(int x=0;x<files.length;x++)
{
if(files[x].isDirectory())
//只要目录中还有目录,就使用同一个列出目录功能的函数完成即可
//在列出过程中出现的还是目录的话,还可以再次调用本功能
showDir(files[x]);
//递归要注意的地方:
//1限定条件
//2注意递归的次数,尽量避免内存溢出。
else
System.out.println(files[x]);
}
}
}
删除带目录的内容
删除原理:
在window中,删除目录从里向外一层一层的删除。
既然是从里向外删除。就需要用到递归。
代码演示:
import java.io.*;
class Lianxi
{
public static void main(String[]args)throws IOException
{
File fir = new File("g:\\yanshiwenjianjia");
removeDir(fir);
}
public static void removeDir(File dir)
{
File[]files = dir.listFiles();
for(int x=0; x<files.length;x++)
{
//判断是否是目录
if(files[x].isDirectory())
removeDir(files[x]);
else
System.out.println(files[x].toString()+":file:"+files[x].delete());
}
System.out.println(dir+":dir:"+dir.delete());
}
}
IO流(Properties)
Properties是hashtable的子类
也就是说它具备了map集合的特点,而且它里面存储的键值对都是字符串。
是集合中和IO技术相结合的集合容器。
该对象的特点:可以用于键值对形式的配置文件。
那么在加载数据时,需要数据有固定格式:键=值
代码演示:
import java.io.*;
import java.util.*;
class Lianxi
{
public static void main(String[] args)throws IOException
{
loadDemo();
}
//演示load方法原理
public static void loadDemo()throws IOException
{
Properties prop = new Properties();
FileInputStream fis = new FileInputStream("g:\\info.txt");
//通过load方法将流中的数据加载进集合
prop.load(fis);
//System.out.println(prop);
prop.setProperty("lisi","39" );
FileOutputStream fos = new FileOutputStream("g:\\info.txt");
prop.store(fos,"haha");
prop.list(System.out);
fos.close();
fis.close();
}
//演示,如何将流中的数据存储到集合中。
//想要将硬盘上的一个文件中的键值数据存到集合中进行操作。
public static void method_1()throws IOException
{
//思路:1用一个流和文件关联
//2读取一行数据,将该行数据用=号进行切割
//3等号左边作为键,右边作为值存到Properties集合中即可
BufferedReader bufr = new BufferedReader(new FileReader("G:\\info.txt"));
String line = null;
Properties prop = new Properties();
while((line=bufr.readLine())!=null)
{
String[]arr= line.split("=");
//System.out.println(arr[0]+"..."+arr[1]);
prop.setProperty(arr[0],arr[1]);
}
bufr.close();
System.out.println(prop);
}
//设置和获元素
public static void setAndGet()
{
//创建一个Properties集合对象
Properties prop = new Properties();
//用setProperty方法设置键值对
prop.setProperty("zhangsan","30");
prop.setProperty("lisi","39");
//System.out.println(prop);//输出结果{zhangsan=30, lisi=39}
//通过getProperty方法在用集合中某个元素的键来获取对应的值
String value = prop.getProperty("lisi");
//System.out.println(value);//输出结果对应的值39
//通过setProperty方法将集合中指定的键对应的值进行修改
prop.setProperty("lisi","89");
//通过stringPropertyNames方法集合对象中的键集
Set<String>names = prop.stringPropertyNames();
//遍历集合
for(String s : names)
{
System.out.println(s+"..."+prop.getProperty(s));//输出结果为prop集合中的键集zhangsan lisi
}
}
}
IO流(PrintWriter)
打印流:该流提供打印方法,可以将各种数据类型的数据都原样打印
字节打印流
PrintStream
构造函数可以接受的参数类型:
1 File对象 File
2 字符串路径 String
3 字节输出流OutputStream
字符打印流
PrintWriter
构造函数可以接受的参数类型:
1 File对象 File
2 字符串路径 String
3 字节输出流OutputStream
4 字符输出流Writer
代码演示:
import java.io.*;
class Lianxi
{
public static void main(String[] args)throws IOException
{
//创建一个键盘录入
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new FileWriter("g:\\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(也称为序列流)
代码演示:
import java.io.*;
import java.util.*;
class Lianxi
{
public static void main(String[] args)throws IOException
{
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("g:\\1.txt"));
v.add(new FileInputStream("g:\\2.txt"));
v.add(new FileInputStream("g:\\3.txt"));
Enumeration<FileInputStream>en = v.elements();
//创建序列流对象
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("G:\\heji.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
}
演示切割文件
代码演示:
import java.util.*;
import java.io.*;
class Lianxi
{
public static void main(String[] args)throws IOException
{
//切割文件
// splitFile();
//合并文件
//merge();
}
public static void merge()throws IOException
{
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int x=1; x<3; x++)
{
al.add(new FileInputStream("g:\\splitFiles\\"+x+".part"));
}
final Iterator<FileInputStream> it = al.iterator();
Enumeration<FileInputStream>en = new Enumeration<FileInputStream>()
{
public boolean hasMoreElements()
{
return it.hasNext();
}
public FileInputStream nextElement()
{
return it.next();
}
};
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("g:\\splitFiles\\0.png");
byte[]buf = new byte[1024];
int len = 0;
while((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
public static void splitFile()throws IOException
{
FileInputStream fis = new FileInputStream("g:\\yanshi.png");
FileOutputStream fos = null;
byte[]buf = new byte[1024*1024];
int len = 0;
int count = 1;
while((len=fis.read(buf))!=-1)
{
fos= new FileOutputStream("g:\\splitfiles\\"+(count++)+"1.part");
fos.write(buf,0,len);
fos.close();
}
fis.close();
}
}
IO流ObjectInputStream与ObjectOutputStream(对象的序列化)
代码演示:
import java.io.*;
class Lianxi
{
public static void main(String[] args)throws Exception
{
//WriteObj();
readObj();
}
public static void readObj()throws Exception
{
ObjectInputStream ois =
new ObjectInputStream(new FileInputStream("g:\\obj.txt"));
Person p = (Person)ois.readObject();
System.out.println(p);
ois.close();
}
public static void WriteObj()throws IOException
{
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("g:\\obj.txt"));
oos.writeObject(new Person("lisi",399,"la"));
oos.close();
}
}
import java.io.*;
class Person implements Serializable
{
//给类手动定义一个序列号。
public static final long serialVersionUID= 42L;
private String name;
//被transien修饰后虽然还是在堆内存中,但是不能被序列化。
transient int age;
//被静态修饰后是不能被序列化的
static String country = "us";
Person(String name,int age,String country)
{
this.name = name;
this.age = age;
this.country = country;
}
public String toString()
{
return name+":"+age+":"+country;
}
}
IO流中的其他类(管道流)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 Lianxi
{
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();
}
}
IO流(RandomAccessFile)
随机访问文件,自身具备读写的方法。
该类不算是IO体系中的子类,而是直接继承自Object。
但是它IO包中的成员,因为它具备读和写功能
内部封装了一个数据,而且通过指针对数组的元素进行操作。
可以通过getFilePointer获取指针位置,
同时也可以通过seek改变指针的位置
其实完成读写的原理,就是内部封装了字节输出和输入流
通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式:自读”r”,读写“rw”等
而且该对象的构造函数要操作的文件不存在会自动创建,如果存在则不会覆盖。
如果模式为只读“r”不会创建文件,会去读取一个存在文件,如果该文件不存在,则会出现异常,如果模式为“rw”那么操作文件不存在,会自动创建,如果存在则不会覆盖。
代码演示:
import java.io.*;
class Lianxi
{
public static void main(String[] args)throws IOException
{
//readFile();
//writerFile();
writerFile_2();
}
public static void readFile()throws IOException
{
RandomAccessFile raf = new RandomAccessFile("g:\\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 writerFile()throws IOException
{
RandomAccessFile raf = new RandomAccessFile("g:\\ran.txt","rw");
raf.write("李四".getBytes());
raf.writeInt(97);
raf.write("王五".getBytes());
raf.writeInt(99);
raf.close();
}
public static void writerFile_2()throws IOException
{
RandomAccessFile raf = new RandomAccessFile("g:\\ran.txt","rw");
raf.seek(8*0);
raf.write("周七".getBytes());
raf.writeInt(103);
raf.close();
}
}
操作基本数据类型的流对象DataInputStream与DataOutputStream
代码演示:
import java.io.*;
class Lianxi
{
public static void main(String[] args)throws IOException
{
//readData();
//writeUTFDemo();
//OutputStreamWriter osw = newOutputStreamWriter(new FileOutputStream("g:\\gbk.txt"),"gbk");
//osw.write("你好");
//osw.close();
readUTFDemo();
}
public static void readUTFDemo()throws IOException
{
DataInputStream dis = new DataInputStream(new FileInputStream("g:\\data.txt"));
String s = dis.readUTF();
System.out.println(s);
dis.close();
}
public static void writeUTFDemo()throws IOException
{
DataOutputStream dos =
new DataOutputStream(new FileOutputStream("g:\\utfdata.txt"));
dos.writeUTF("你好");
dos.close();
}
public static void readData()throws IOException
{
DataInputStream dis = new DataInputStream(new FileInputStream("g:\\data.txt"));
//下面的读取类型的顺序一定按照输入的时的类型顺序
int num = dis.readInt();
Boolean b = dis.readBoolean();
Double d = dis.readDouble();
System.out.println("num:"+num);
System.out.println("b:"+b);
System.out.println("d:"+d);
dis.close();
}
public static void writeData()throws IOException
{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("g:\\data.txt"));
dos.writeInt(234);
dos.writeBoolean(true);
dos.writeDouble(9887.543);
dos.close();
}
}
用于操作字节数组的流对象
ByteArrayInputStream:在构造的时候,需要接收数据源是一个字节数组。
ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象内部已经封装了可变长度的字节数组。
因为这两个流对象都操作的是数组,并没有使用系统资源,所以不用进行close关闭
在流操作规律讲解中:
原设备:
键盘:System.in 硬盘 FileStream 内存ArrayStream
目的设备:
控制台 System.out 硬盘 FileStream 内存ArrayStream
代码演示:
import java.io.*;
class Lianxi
{
public static void main(String[] args)throws IOException
{
//数据源。
ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFG".getBytes());
//数据目的
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int ch = 0;
while((ch=bis.read())!=-1)
{
bos.write(ch);
}
System.out.println(bos.size());
System.out.println(bos.toString());
//writeTo方法可以将内存中的数据写出到硬盘文件当中
bos.writeTo(new FileOutputStream("g:\\aaaaa.txt"));
}
}
转换流的字符编码
编码:字符串变成字节数组。
解码:字节数组变成字符串
String-->Byte[]; 字符串对象.getBytes(charsetName);//默认情况下是GBK
Byte[];-->String newString(Byte[],charsetName );
代码演示:
import java.util.*;
public class Yanshi
{
public static void main(String[] args)throws Exception
{
String s = "哈哈";
//对”你好“这个字符串用getBytes方法进行编码传给一个byte数组。
byte[] b1 = s.getBytes("gbk");
//用Array.toString方法获取b1数组里面的数字
System.out.println(Arrays.toString(b1));
//输出是默认GBK的编码表,编码数字
//用new String 将b1里的表码表数字进行解码
String s1 = new String(b1,"ISO8859-1");
System.out.println("s1="+s1);
//发现通过用ISO8859-1的码表解码出错,那么对乱码s1重新进行ISO8859-1的方式编码
byte[] b2 = s1.getBytes("iso8859-1");
//获取到这个编码之后的数字
System.out.println(Arrays.toString(b2));
//再用gbk的码表对b2这个数组里面的数字进行解码
String s2 = new String(b2,"gbk");
System.out.println("s2="+s2);
}
}