黑马程序员-java基础学习IO流4

------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ---------

File类
用来将文件或文件夹封装成对象
方便对文件或文件夹的属性信息进行操作
File对象可以作为参数传递给流的构造函数
了解File类中的常用方法


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


boolean mkdir():创建文件夹。
boolean mkdirs():创建多级文件夹。
2,删除。
boolean delete():删除失败返回false。如果文件正在被使用,则删除不了返回falsel。
void deleteOnExit();在程序退出时删除指定文件。




3,判断。
boolean exists() :文件是否存在.
//记住在判断文件对象是否是文件或者目的时,必须要先判断该文件对象封装的内容是否存在。
//通过exists判断。
isFile():是否是文件
isDirectory();是否是目录
isHidden();文件是否是一个隐藏文件
isAbsolute();此抽象路径是否是绝对路径


File f = new File("d:\\java1223\\day20\\file2.txt");绝对路径
File f = new File("file2.txt");不是绝对路径
4,获取信息。
getName():获取文件或目录的名称
getPath():(封装什么路径返回就什么路径)将路径名转换为一个路径名字符串
getParent()://该方法返回的是绝对路径中的父目录。如果获取的是相对路径,返回null。
   //如果相对路径中有上一层目录那么该目录就是返回结果。


getAbsolutePath() 返回绝对路径名字符串
long lastModified() 返回最后一次修改时间
long length() 文件大小
*/


File[]  listRoots()列出可用的文件系统根(电脑上C盘,D盘。。)。返回文件数组


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


练习:
/*
列出指定目录下文件或者文件夹,包含子目录中的内容。
也就是列出指定目录下所有内容。


因为目录中还有目录,只要使用同一个列出目录功能的函数完成即可。
在列出过程中出现的还是目录的话,还可以再次调用本功能。
也就是函数自身调用自身。
这种表现形式,或者编程手法,称为递归。


递归要注意:
1,限定条件。


2,要注意递归的次数。尽量避免内存溢出。


*/


import java.io.*;
class  Test1
{
public static void main(String[] args) 
{
File file=new File("D:\\java\\javacx");
show(file);
}
public static void show(File dir)
{
File[] f=dir.listFiles();
for(int x=0;x<f.length;x++)
{
if(f[x].isDirectory())
show(f[x]);
else
System.out.println(f[x]);
}
}
}






/*
删除一个带内容的目录。
删除原理:
在window中,删除目录从里面往外删除的。


既然是从里往外删除。就需要用到递归。
*/
import java.io.*;
class  RemoveDir
{
public static void main(String[] args) 
{

File dir = new File("d:\\testdir");
removeDir(dir);
}


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());
}


}


/*
练习
将一个指定目录下的java文件的绝对路径,存储到一个文本文件中。
建立一个java文件列表文件。


思路:
1,对指定的目录进行递归。
2,获取递归过程所以的java文件的路径。
3,将这些路径存储到集合中。
4,将集合中的数据写入到一个文件中。


*/


import java.io.*;
import java.util.*;
class  Test2
{
public static void main(String[] args) 
{
File dir=new File("D:\\java\\javacx");
List<File> list=new ArrayList<File>();
fileToList(dir,list);
//System.out.println(list.size());
File file=new File(dir,"java.txt");
writeToFile(list,file.toString());


}
//将指定目录下Java文件存入集合中
public static void fileToList(File dir,List<File> list)
{
File[] files=dir.listFiles();
for(File file : files)//高级for循环
{
if(file.isDirectory())
fileToList(file,list);
else
{
if(file.getName().endsWith(".java"))
list.add(file);
}
}
}
//将集合中数据存入文件中
public static void writeToFile(List<File> list,String javaListFile)
{
BufferedWriter bufw=null;
try
{
bufw=new BufferedWriter(new FileWriter(javaListFile));
for(File f : list)
{
String path=f.getAbsolutePath();
bufw.write(path);
bufw.newLine();
bufw.flush();
}


}
catch (IOException e)
{
}
finally
{
try
{
if(bufw!=null)
bufw.close();
}
catch (IOException e)
{
}
}
}
}


Properties是hashtable的子类。
也就是说它具备map集合的特点。而且它里面存储的键值对都是字符串。


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


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


那么在加载数据时,需要数据有固定格式:键=值。
05.IO流(Properties简述)




 1.Map ---> Hashtable---->Properties类(java.util包)
  1)Properties是Hashtable的子类。
   也就是说它具备map集合的特点。而且它里面存储的键值对都是字符串。


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


   该对象的特点:可以用于键值对形式的配置文件。
        但在加载数据时,需要数据有固定格式:键=值。
  2)构造方法: 
   Properties() 
      创建一个无默认值的空属性列表。 
   Properties(Properties defaults) 
      创建一个带有指定默认值的空属性列表。
  3)方法:
   <1>String getProperty(String key) 
      用指定的键在此属性列表中搜索属性。 
   <2>String getProperty(String key, String defaultValue) 
      用指定的键在属性列表中搜索属性。 
   <3>Object setProperty(String key, String value) 
      调用 Hashtable 的方法 put。 
   <4>Set<String> stringPropertyNames() 
      返回此属性列表中的键集,其中该键及其对应值是字符串,
      如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。




06.IO流(Properties存取配置文件)


 1.Properties的方法:
  1)void list(PrintStream out) 
     将属性列表输出到指定的输出流。 
  2)void list(PrintWriter out) 
     将属性列表输出到指定的输出流。 
  3)void load(InputStream inStream) 
     从输入流中读取属性列表(键和元素对)。 
  4)void load(Reader reader) 
     按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。 
  5)void store(OutputStream out, String comments)//comments为注释 
     以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,
     将此 Properties 表中的属性列表(键和元素对)写入输出流。 
  6)void store(Writer writer, String comments) 
     以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)
     写入输出字符。


/*
用于记录应用程序运行次数。
如果使用次数已到,那么给出注册提示。


很容易想到的是:计数器。
可是该计数器定义在程序中,随着程序的运行而在内存中存在,并进行自增。
可是随着该应用程序的退出,该计数器也在内存中消失了。


下一次在启动该程序,又重新开始从0计数。
这样不是我们想要的。


程序即使结束,该计数器的值也存在。
下次程序启动在会先加载该计数器的值并加1后在重新存储起来。


所以要建立一个配置文件。用于记录该软件的使用次数。


该配置文件使用键值对的形式。
这样便于阅读数据,并操作数据。


键值对数据是map集合。
数据是以文件形式存储,使用io技术。
那么map+io -->properties.


配置文件可以实现应用程序数据的共享。






*/
import java.io.*;
import java.util.*;
class  RunCount
{
public static void main(String[] args) throws IOException
{
Properties prop = new Properties();


File file = new File("count.ini");
if(!file.exists())
file.createNewFile();

FileInputStream fis = new FileInputStream(file);


prop.load(fis);



int count = 0;
String value = prop.getProperty("time");

if(value!=null)
{
count = Integer.parseInt(value);
if(count>=5)
{
System.out.println("您好,使用次数已到,拿钱!");
return ;
}


}


count++;


prop.setProperty("time",count+"");


FileOutputStream fos = new FileOutputStream(file);


prop.store(fos,"");


fos.close();
fis.close();

}
}




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


字节打印流:
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();


}
}


IO流(合并流)




 InputStream ---> SequenceInputStream类(java.io包)
  1)SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,
  并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,
  直到到达包含的最后一个输入流的文件末尾为止。
  2)构造方法摘要 
   <1>SequenceInputStream(Enumeration<? extends InputStream> e) 
     通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。 
   <2>SequenceInputStream(InputStream s1, InputStream s2) 
     通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。 




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


Vector<FileInputStream> v = new Vector<FileInputStream>();



v.add(new FileInputStream("c:\\1.txt"));
v.add(new FileInputStream("c:\\2.txt"));
v.add(new FileInputStream("c:\\3.txt"));


Enumeration<FileInputStream> en = v.elements();


SequenceInputStream sis = new SequenceInputStream(en);


FileOutputStream fos = new FileOutputStream("c:\\4.txt");


byte[] buf = new byte[1024];


int len =0;
while((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}


fos.close();
sis.close();
}
}


IO流(对象的序列化)




 1.OutPutStream ---> 类 ObjectOutputStream(java,io包)


 1)ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。
  可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。
  如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。


  只能将支持 java.io.Serializable 接口的对象写入流中。每个 serializable 对象的类都被编码,
  编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。
 2)构造方法摘要 
   <1>protected  ObjectOutputStream() 
     为完全重新实现 ObjectOutputStream 的子类提供一种方法,
     让它不必分配仅由 ObjectOutputStream 的实现使用的私有数据。 
   <2>ObjectOutputStream(OutputStream out)  
     创建写入指定 OutputStream 的 ObjectOutputStream。
  3)特有方法:
   <1>void writeObject(Object obj) 
     将指定的对象写入 ObjectOutputStream。 
   <2>void writeInt(int val) 
     写入一个 32 位的 int 值。


 2.InputStream ---> 类 ObjectInputStream (java.io包)


  1)ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。


  ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,
  可以为应用程序提供对对象图形的持久存储。ObjectInputStream 用于恢复那些以前序列化的对象。
  其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。


  objectInputStream 确保从流创建的图形中所有对象的类型与 Java 虚拟机中显示的类相匹配。
  使用标准机制按需加载类。


  只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能从流读取。
  2)构造方法摘要 
  protected  ObjectInputStream() 
     为完全重新实现 ObjectInputStream 的子类提供一种方式,让它不必分配仅由 ObjectInputStream 的实现使用的私有数据。 
  ObjectInputStream(InputStream in) 
     创建从指定 InputStream 读取的 ObjectInputStream。 
  3)特有方法:
  Object readObject() 
     从 ObjectInputStream 读取对象。
     
 3. 接口 Serializable (java.io包)
   1)public interface Serializable类通过实现 java.io.Serializable 接口以启用其序列化功能。
  未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。
  序列化接口没有方法或字段,仅用于标识可序列化的语义。
   2)可序列化类可以通过声明名为 "serialVersionUID" 的字段
    (该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:




  ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
  如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值
 4.注意:
 1)实现了Serializable接口的类都会有一个UID的序列号(java自动生成)标示,类改变,序列号也会改变。
    要想改变类而不改变序列号,可手动给类定义一个固定的序列号(方便序列化)。方法就是:
    显式声明其自己的 serialVersionUID:


  public static final long serialVersionUID = 42L;


 2)静态变量不能被序列化,因为静态在方法区中,而对象是在堆里。序列化是对堆中的对象进行的。
 3)如果对堆中的成员也不想进行序列的化的话。只需加上关键字transient修饰就可以了。
 4)因为对象文件看不懂,也没必要打开看。所以文件名一般不存成obj.txt,而存成Person.object  。
 5)当Person类改变时,会发生InvalidClassException:异常,同时抛出的还有IOException。为方便演示故只抛出个Exception.
例子:
import java.io.*;
class ObjectStreamDemo 
{
public static void main(String[] args) throws Exception
{
//writeObj();
readObj();
}
//读取对象
public static void readObj()throws Exception
{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("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("obj.txt"));


oos.writeObject(new Person("lisi0",399,"kr"));


oos.close();
}
}




管道流


PipedInputStream和PipedOutputStream
  输入输出可以直接进行连接,通过结合线程使用。
1)管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,
  数据由某个线程从 PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream。
  不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。管道输入流包含一个缓冲区,
  可在缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在,
  则认为该管道已损坏。
  2)构造方法摘要 
  <1>PipedInputStream() 
     创建尚未连接的 PipedInputStream。 
  <2>PipedInputStream(int pipeSize) 
     创建一个尚未连接的 PipedInputStream,并对管道缓冲区使用指定的管道大小。 
  <3>PipedInputStream(PipedOutputStream src) 
     创建 PipedInputStream,使其连接到管道输出流 src。 
  <4>PipedInputStream(PipedOutputStream src, int pipeSize) 
     创建一个 PipedInputStream,使其连接到管道输出流 src,并对管道缓冲区使用指定的管道大小。 
  3)特有方法:
  void connect(PipedOutputStream src) 
     使此管道输入流连接到管道输出流 src。


 2.OutputStream ---> PipedOutputStream类(java.io包)


  1)可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,
  数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。
  不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。
  如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,
  则该管道被视为处于 毁坏 状态
  2)构造方法摘要 
  <1>PipedOutputStream() 
     创建尚未连接到管道输入流的管道输出流。 
  <2>PipedOutputStream(PipedInputStream snk) 
     创建连接到指定管道输入流的管道输出流。 
  3)特有方法:
  void connect(PipedInputStream snk) 
     将此管道输出流连接到接收者。


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();




}
}




IO流(RandomAccessFile)


 1. RandomAccessFile类:
  随机访问文件,自身具备读写的方法。
  通过skipBytes(int x),seek(int x)来达到随机访问。


  该类不算是IO体系中的子类。
  而是直接继承Object.


  但是它是IO包中成员。因为它具备读写功能。
  内部封装了一个数组。而且通过指针对数组的元素进行操作。
  可以通过getFilePointer获取指针位置。
  同时可以通过seek改变指针的位置。


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


  通过构造函数可以看出,该类只能操作文件。
  而且操作文件还有模式:只读r,读写rw等。


  如果模式为只读r.不会创建文件。会去读取一个已存在文件。如果该文件不存在。则会出现异常。
  如果模式为rw.操作的文件不存在,会自动创建,如果存在,则不会覆盖。


 2.Object ----> RandomAccessFile类:
  1)此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的
  一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,
  并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;
  输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。
  写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,
  并通过 seek 方法设置。


  通常,如果此类中的所有读取例程在读取所需数量的字节之前已到达文件末尾,
  则抛出 EOFException(是一种 IOException)。如果由于某些原因无法读取任何字节,
  而不是在读取所需数量的字节之前已到达文件末尾,则抛出 IOException,而不是 EOFException。
  需要特别指出的是,如果流已被关闭,则可能抛出 IOException
  2)构造方法摘要 
  <1>RandomAccessFile(File file, String mode) 
     创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。 
  <2>RandomAccessFile(String name, String mode) 
     创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。 
  3)特有方法:
  <1>void writeInt(int v) 
     按四个字节将 int 写入该文件,先写高字节。 
  <2>int skipBytes(int n) 
     尝试跳过输入的 n 个字节以丢弃跳过的字节。 
  <3>void write(byte[] b) 
     将 b.length 个字节从指定 byte 数组写入到此文件,并从当前文件指针开始。 
  <4>void write(int b) 
     向此文件写入指定的字节。(写两个字节) 
  <5>void writeBoolean(boolean v) 
     按单字节值将 boolean 写入该文件。 
  <6>void writeByte(int v) 
     按单字节值将 byte 写入该文件。 
  <7>void writeBytes(String s) 
     按字节序列将该字符串写入该文件。 
  <8>void seek(long pos) 
     设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。 
  <9>int readInt() 
     从此文件读取一个有符号的 32 位整数。 
  <10>String readLine() 
     从此文件读取文本的下一行。 
  <11>long getFilePointer() 
     返回此文件中的当前偏移量。 
  <12>long length() 
     返回此文件的长度。 
  <13>int read() 
     从此文件中读取一个数据字节。 
  <14>int read(byte[] b) 
     将最多 b.length 个数据字节从此文件读入 byte 数组。 
  <15>void close() 
     关闭此随机访问文件流并释放与该流关联的所有系统资源。








IO流(操作基本数据类型的流对象DataStream)




   DataInputStream与DataOutputStream


   可以用于操作基本数据类型的数据的流对象。
 1.OutputStream ---> DataOutputStream类


  1)数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后,
  应用程序可以使用数据输入流将数据读入。 
  2)构造方法摘要 
  DataOutputStream(OutputStream out) 
     创建一个新的数据输出流,将数据写入指定基础输出流。 
  3)特有方法:
  void writeBoolean(boolean v) 
     将一个 boolean 值以 1-byte 值形式写入基础输出流。 
  void writeDouble(double v) 
     使用 Double 类中的 doubleToLongBits 方法将 double 参数转换为一个 long 值,
     然后将该 long 值以 8-byte 值形式写入基础输出流中,先写入高字节。 
  void writeInt(int v) 
     将一个 int 值以 4-byte 值形式写入基础输出流中,先写入高字节。 
  void writeUTF(String str) 
     以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。 
 2.InputStream ---> DataInputStream类


  1)数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。
  应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。


  DataInputStream 对于多线程访问不一定是安全的。 线程安全是可选的,它由此类方法的使用者负责
  2)构造方法摘要 
  DataInputStream(InputStream in) 
     使用指定的底层 InputStream 创建一个 DataInputStream。 
  3)特有方法:
  boolean readBoolean() 
     参见 DataInput 的 readBoolean 方法的常规协定。 
  double readDouble() 
     参见 DataInput 的 readDouble 方法的常规协定。 
  int readInt() 
     参见 DataInput 的 readInt 方法的常规协定。 
  String readUTF() 
     参见 DataInput 的 readUTF 方法的常规协定。


 3.注意UTF与UTF-8的差别:
   UTF-8是6个字节的两字。而UTF是8个字节的两字。
   null 字节 '\u0000' 是用 2-byte 格式而不是 1-byte 格式编码的,因此已编码的字符串中决不会有嵌入的 null。


IO流(ByteArrayStream)


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


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


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


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




在流操作规律讲解时:


源设备,
键盘 System.in,硬盘 FileStream,内存 ArrayStream。
目的设备:
控制台 System.out,硬盘FileStream,内存 ArrayStream。


 2.InputStream ---> ByteArrayInputStream类


  1)ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。
  内部计数器跟踪 read 方法要提供的下一个字节。


  关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
  2)构造方法摘要 
  ByteArrayInputStream(byte[] buf) 
     创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。 
  ByteArrayInputStream(byte[] buf, int offset, int length) 
     创建 ByteArrayInputStream,使用 buf 作为其缓冲区数组。 
  3)方法摘要 
   int available() 
     返回可从此输入流读取(或跳过)的剩余字节数。 
   int read() 
     从此输入流中读取下一个数据字节。 
   int read(byte[] b, int off, int len) 
     将最多 len 个数据字节从此输入流读入 byte 数组。 
   long skip(long n) 
     从此输入流中跳过 n 个输入字节。 
 3.OutputStream ---> ByteArrayOutputStream类


  1)此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。
  可使用 toByteArray() 和 toString() 获取数据。


  关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
  2)构造方法摘要 
  ByteArrayOutputStream() 
     创建一个新的 byte 数组输出流。 
  ByteArrayOutputStream(int size) 
     创建一个新的 byte 数组输出流,它具有指定大小的缓冲区容量(以字节为单位)。 
  3)方法摘要 
  void close() 
     关闭 ByteArrayOutputStream 无效。 
  void write(byte[] b, int off, int len) 
     将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此 byte 数组输出流。 
  void write(int b) 
     将指定的字节写入此 byte 数组输出流。 
  void writeTo(OutputStream out) 
     将此 byte 数组输出流的全部内容写入到指定的输出流参数中,这与使用 out.write(buf, 0, count) 调用该输出流的 write 方法效果一样。 
  int size() 
     返回缓冲区的当前大小。 
  byte[] toByteArray() 
     创建一个新分配的 byte 数组。 
  String toString() 
     使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。




import java.io.*;
class ByteArrayStream 
{
public static void main(String[] args) 
{
//数据源。
ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFD".getBytes());


//数据目的
ByteArrayOutputStream bos = new ByteArrayOutputStream();


int by = 0;


while((by=bis.read())!=-1)
{
bos.write(by);
}






System.out.println(bos.size());
System.out.println(bos.toString());


//bos.writeTo(new FileOutputStream("a.txt"));


}
}


IO流(转换流的字符编码)


 1.字符编码


  字符流的出现为了方便操作字符。
  更重要的是加入了编码转换。
  通过子类转换流来完成。
   InputStreamReader
   OutputStreamWriter
  在两个对象进行构造的时候可以加入字符集。


 2.编码的由来:


  计算机只能识别二进制数据,早期由来是电信号。
  为了方便应用计算机,让它可以识别各个国家的文字。
  就将各个国家的文字用数字来表示,并一一对应,形成一张表。
  这就是编码表。


 3.常见的编码表


  1)ASCII:美国标准信息交换码。
    用一个字节的7位可以表示。
  2)ISO8859-1:拉丁码表,欧洲码表。
    用一个字节的8位表示。
  3)GB2312:中国的中文编码表。
  4)GBK:中国的中文编码表升级,融合了更多的中文文字符号。
  5)Unicode:国际标准码,融合了多种文字。
    所有文字都用两个字节来表示,Java语言使用的就是unicode.
  6)UTF-8:最多用三个字节来表示一个字符。
  ......
字符编码


 1.编码:字符串变成字节数组
   解码:字节数组变成字符串。


   String --> byte[]: str.getBytes(charsetName);


   byte[] ---> String : new String(byte[],charsetName);


 2.用到的方法:
  1)String类(java.lang包)
   <1>构造方法摘要 
  String() 
     初始化一个新创建的 String 对象,使其表示一个空字符序列。 
  String(byte[] bytes) 
     通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。 
  String(byte[] bytes, Charset charset) 
     通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String。 
   <2>特有方法:
  byte[] getBytes() 
     使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 
  byte[] getBytes(Charset charset) 
     使用给定的 charset 将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。


  2)Arrays类(java.util包)
  static String toString(byte[] a) 
     返回指定数组内容的字符串表示形式。 
  static String toString(Object[] a) 
     返回指定数组内容的字符串表示形式。




IO流综合练习
/*
有五个学生,每个学生有3门课的成绩,
从键盘输入以上数据(包括姓名,三门课成绩),
输入的格式:如:zhagnsan,30,40,60计算出总成绩,
并把学生的信息和计算出的总分数高低顺序存放在磁盘文件"stud.txt"中。


1,描述学生对象。
2,定义一个可操作学生对象的工具类。


思想:
1,通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象。
2,因为学生有很多,那么就需要存储,使用到集合。因为要对学生的总分排序。
所以可以使用TreeSet。
3,将集合的信息写入到一个文件中。




*/


import java.io.*;
import java.util.*;


class Student implements Comparable<Student>
{
private String name;
private int ma,cn,en;
private int sum;


Student(String name,int ma,int cn,int en)
{
this.name = name;
this.ma = ma;
this.cn = cn;
this.en = en;
sum = ma + cn + en;
}




public int compareTo(Student s)
{
int num = new Integer(this.sum).compareTo(new Integer(s.sum));
if(num==0)
return this.name.compareTo(s.name);
return num;
}






public String getName()
{
return name;
}
public int getSum()
{
return sum;
}


public int hashCode()
{
return name.hashCode()+sum*78;


}
public boolean equals(Object obj)
{
if(!(obj instanceof Student))
throw new ClassCastException("类型不匹配");
Student s = (Student)obj;


return this.name.equals(s.name) && this.sum==s.sum;
}


public String toString()
{
return "student["+name+", "+ma+", "+cn+", "+en+"]";
}
}


class StudentInfoTool
{
public static Set<Student> getStudents()throws IOException
{
return getStudents(null);
}


public staticSet<Student> getStudents(Comparator<Student>cmp)throwsIOException
{
BufferedReader bufr = 
new BufferedReader(new InputStreamReader(System.in));


String line = null;

Set<Student> stus  = null;
if(cmp==null)
stus = new TreeSet<Student>();
else
stus = new TreeSet<Student>(cmp);
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;

String[] info = line.split(",");

Student stu = new Student(info[0],Integer.parseInt(info[1]),
Integer.parseInt(info[2]),
Integer.parseInt(info[3]));



stus.add(stu);
}


bufr.close();


return stus;
}


public static void write2File(Set<Student> stus)throws IOException
{
BufferedWriter bufw = new BufferedWriter(new FileWriter("stuinfo.txt"));


for(Student stu : stus)
{
bufw.write(stu.toString()+"\t");
bufw.write(stu.getSum()+"");
bufw.newLine();
bufw.flush();
}


bufw.close();


}
}

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


Comparator<Student> cmp = Collections.reverseOrder();


Set<Student> stus = StudentInfoTool.getStudents(cmp);


StudentInfoTool.write2File(stus);
}
}


------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ---------









 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值