读取键盘录入
System.out:对应的是标准输出设备,控制台
System.in:对应的是标准输入设备,键盘
需求:
通过键盘录入数据。
当录入一行数据后,就将该行数据进行打印。
如果录入的数据是over,那么停止录入。
通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。
也就是readLine方法。
那么能不能直接使用readLine方法来完成键盘录入一行数据的读取呢?
readLine方法是字符流BufferedReader类中的方法。
而键盘录入的read方法时字节流InputStream的方法。
那么能不能将字节流转成字符流,再使用字符流缓冲区的readLine方法呢?
import java.io.*;
class ReadIn
{
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);
}
in.close();
}
}
因为BufferedReader 与BufferedWriter中存在整行操作的方法。
readLine();writeLine();
import java.io.*;
class TransStreamDemo
{
public static void main(String[] args) throws IOException
{
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;
System.out.println(line.toUpperCase());
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
}
}
源:键盘录入
目的:控制台
2,需求:想把键盘录入的数据存储到一个文件中。
源:键盘录入
目的:文件
3,需求:想要将一个文件的数据打印在控制台上。
源:文件
目的:控制台
流操作的基本规律:
最痛苦的就是流对象有很多,不知道该用哪个。
通过三个明确来完成。
1,明确源和目的。
源:输入流。 InputStream Reader
目的:输出流。 OutputStream Writer
2,明确操作的数据是否是纯文本。
是:字符流。
不是:字节流。
3,当体系明确后,再明确要使用哪个具体的对象。
通过设备来进行区分。
源设备:内存,硬盘,键盘。
目的设备:内存,硬盘,控制台。
1,将一个文本文件中的数据存储到另一个文件中,复制文件。
源:因为是源,所以使用读取流。 InputStream Reader
是不是操作文本文件:是!这时就可以选择Reader
这样体系就明确了。
接下来明确要使用该体系中的哪个对象。
明确设备:硬盘上的一个文件。
Reader体系中可以操作文件的对象FileReader
是否需要提高效率:是! 加入Reader体系中的缓冲区:BufferedReader
FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);
目的:OutputStream Writer
是不是纯文本:是!所以用Writer
设备:硬盘上的一个文件。
Writer体系中可以操作文件的对象FileWriter
是否需要提高效率:是! 加入Reader体系中的缓冲区:BufferedWriter
FileWriter fw = new FileReader("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);
练习:将一个图片文件中的数据存储到另一个文件中,复制文件。要按照以上格式自己完成三个明确。
源:InputStream Reader
是不是操作文本文件:不是! InputStream
设备:硬盘上的一张图片 FileInputStream
目的:OutputStream Writer
是不是操作文本文件:不是! OutputStream
设备:硬盘上的一张图片 FileOutputStream
--------------------------------------------------------------------
2,需求:将键盘录入的数据保存到一个文件中。
这个需求中,有源和目的都存在,那么分别分析:
源:InputStream Reader
是不是纯文本?是! Reader
设备:键盘,对应的对象System.in
不是选择Reader吗?System.in对应的不是字节流吗?
为了操作键盘的文本数据方便,转成字符流按照字符串操作最方便。
所以既然明确了Reader,那么就将System.in转换成字符流。
用了Reader体系中转换流,InputStreamReader
需要提高效率吗?需要!BufferedReader
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader bufr = new BufferedReader(isr);
目的:OutputStream Writer
是不是纯文本?是! Writer
设备:硬盘上的一个文件。使用FileWriter
需要提高效率吗?需要!BufferedWriter
FileWriter fw = new FileWriter("c.txt");
BufferedWriter bufw = new BufferedWriter(fw);
*************************************************************************
扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存储到文件中。
目的:OutputStream Writer
是不是纯文本?是! Writer
设备:硬盘上的一个文件。使用FileWriter
FileWriter使用的是默认编码表:GBK
但是存储时需要加入指定编码表,而指定的编码表只有转换流可以指定。
所以要使用的对象是OutputStreamWriter
而该转换流对象要接收一个字节输出流,而且还可以操作的文件的字节输出流。FileOutputStream
需要提高效率吗?需要!BufferedWriter
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt","UTF-8"));
BufferedWriter bufw = new BufferedWriter(osw);
所以,记住。转换流什么时候使用?
字符和字节的桥梁,通常涉及到字符编码转换时需要用到转换流。
*************************************************************************
练习:将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。
源:InputStream Reader
是不是纯文本?是! Reader
设备:硬盘上的一个文件。使用FileReader
是否需要提高效率?是,BufferedReader
目的:OutputStream Writer
是不是纯文本?是! Writer
设备:控制台,所以使用OutputStreamWriter
是否需要提高效率不?是,BufferedWriter
import java.io.*;
class TransStreamDemo
{
public static void main(String[] args) throws IOException
{
System.setIn(new FileInputStream("文件说明.txt"));
System.setOut(new PrintStream("改变标准输入输出设备.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;
//System.out.println(line.toUpperCase());
bufw.write(line.toString());
bufw.newLine();
bufw.flush();
}
bufr.close();
//test_1();
//test_2();
}
public static void test_2() throws IOException
{
/*
练习:将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。
源:InputStream Reader
是不是纯文本?是! Reader
设备:硬盘上的一个文件。使用FileReader
是否需要提高效率?是,BufferedReader
目的:OutputStream Writer
是不是纯文本?是! Writer
设备:控制台,所以使用OutputStreamWriter
是否需要提高效率不?是,BufferedWriter
*/
BufferedReader bufr = new BufferedReader(new FileReader("文件说明.txt"));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String buf = null;
while ((buf = bufr.readLine())!=null)
{
bufw.write(buf);
bufw.newLine();
bufw.flush();
}
bufr.close();
bufw.close();
}
public static void test_1() throws IOException
{
/*
练习:将一个图片文件中的数据存储到另一个文件中,复制文件。要按照以上格式自己完成三个明确。
源:InputStream Reader
是不是操作文本文件:不是! InputStream
设备:硬盘上的一张图片 FileInputStream
目的:OutputStream Writer
是不是操作文本文件:不是! OutputStream
设备:硬盘上的一张图片 FileOutputStream
*/
FileInputStream fis = new FileInputStream("picture.png");
FileOutputStream fos = new FileOutputStream("picture_new.png");
int len = 0;
byte[] buf = new byte[1024];
while ((len = fis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fis.close();
fos.close();
}
}
1,创建
boolean createNewFile();
在指定位置创建文件,如果该文件已经存在,则不创建文件返回false。
和输出流不一样,输出流对象在建立的时候就会创建文件,而且文件存在时会覆盖。
boolean mkdir();
创建文件夹。
boolean mkdirs();
创建多级文件夹。
2,删除
boolean delete();
删除失败返回false。
void deleteOnExit();
在程序退出时删除指定文件。
3,判断
boolean exists();
文件是否存在。
boolean isFile();
判断是否为文件。
boolean ifDirectory();
判断是否为文件夹。
boolean isHidden();
判断是否为隐藏文件或文件夹。
boolean isAbsolute();
判断是否为绝对路径,如果是绝对路径,即使文件或文件夹不存在,也返回ture。
4,获取信息
getName();
获取名称。
getPath();
获取抽象路径名,相对路径,封装什么返回什么。
getParent();
获取父目录,如果没有返回null。
该方法返回的是绝对路径中的文件父目录,如果是相对路径,就会返回null。
如果相对路径中有上一层目录,那么该目录就是返回结果。"abc\\a.txt"-->getParent();-->abc
String getAbsolutePath();
获取文件或文件夹的绝对路径。
long lastModified();
获取最后修改时间。
long length();
获取指定路径上文件的长度。
boolean renameTo(File f);
重新命名此抽象路径的文件。
String[] list();
String[] list(FilenameFilter filter);
返回指定目录下的所有文件名。
调用list方法的file对象必须是封装了一个目录,该目录还必须存在。
根据过滤器filter返回文件或文件夹名。
File[] listFiles();
File[] listFiles(FileFilter filter);
File[] listFiles(FilenameFilter filter);
返回指定目录下所有文件或文件夹封装成的对象。
根据过滤器filter返回不同的文件或文件夹。
File[] listRoots();
返回所有盘符。
import java.io.*;
class MyFilenameFilter implements FilenameFilter
{
public boolean accept(File dir, String name)
{
return name.endsWith(".java");
}
}
class FileDemo2
{
public static void main(String[] args)
{
//listDemo(new MyFilenameFilter());
listFilesDemo();
}
public static void listFilesDemo()
{
File dir = new File("F:\\javazx\\19");
File[] files = dir.listFiles();
for (File f : files)
{
System.out.println(f.getName()+"\t"+f.length());
}
}
public static void listDemo(FilenameFilter filter)
{
File dir = new File("F:\\javazx\\19");
String[] names = dir.list(filter);
System.out.println(names.length);
for(String name : names)
{
System.out.println(name);
}
}
public static void listDemo()
{
File f = new File("F:\\javazx\\19");
String[] names = f.list();//调用list方法的file对象必须是封装了一个目录,该目录还必须存在
for(String name : names)
{
System.out.println(name);
}
}
public static void listRootsDemo()
{
File[] files = File.listRoots();
for (File f : files)
{
System.out.println(f);
}
}
}
也就是列出指定目录下所有内容。
在列出过程中出现的还是目录的话,还可以再次调用本功能。
也就是函数自身调用自身。
这种表现形式,或者变成手法,称为递归。
递归要注意:
1,限定条件。
2,要注意递归的次数,尽量避免内存溢出
import java.io.*;
class FileDemo3
{
public static void main(String[] args)
{
File dir = new File("F:\\TestDirectory");
showAllFiles(dir,0);
//toBin(6);
//System.out.println(getSum(10));
}
public static String getLevel(int level)
{
StringBuilder sb = new StringBuilder();
for (int x = 0; x<level; x++)
{
sb.append(" ");
}
sb.append("|--");
return sb.toString();
}
public static void showAllFiles(File dir,int level)
{
System.out.println(getLevel(level)+dir.getName());
level++;
File[] files = dir.listFiles();
for(File f : files)
{
if(f.isDirectory())
showAllFiles(f,level);
else
System.out.println(getLevel(level)+f.getName()+" "+f.length());
}
}
public static int getSum(int n)
{
if (n==1)
{
return 1;
}
else
return n+getSum(n-1);
}
//递归简单例子
public static void toBin(int num)
{
if (num>0)
{
toBin(num/2);
System.out.print(num%2);
}
}
}
也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串。
是集合中和IO技术相结合的集合容器。
该对象的特点:可以用于键值对形式的配置文件。
那么在加载数据是,需要数据固定格式:键=值。
特有方法
1、设置
Object setProperty(String key,String value);
//设置键和值,调用Hashtable的方法put
2、获取
String getProperty(String key);
//指定key搜索value
Set<String> stringPropertyName();
//返回属性列表的键集,存入Set集合
3、加载流和存入流
void load(InputStream ism);
//从输入字节流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
void load(Readerreader);
//从输入字符流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
voidlist(PrintStream out);//将属性列表输出到指定的输出流
void store(OutputStreamout,String comments);
//对应load(InputStream )将属性列表(键值对)写入输出流。comments属性列表的描述。
void store(Writerwriter, String comments);
//对应load(Reader)将属性列表(键值对)写入输出流。comments属性列表的描述。
练习:用于记录应用程序运行次数。如果使用次数已到,那么给出注册提示。/*
用于记录应用程序运行次数。
如果使用次数已到,那么给出注册提示。
很容易想到的是:计数器。
可是该计数器定义在程序中,随着程序的运行而在内存中存在,并进行自增。
可是随着该应用程序的退出,该技术器也在内存中消失了。
下一次再启动改程序,又重新开始从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
字符打印流:
PrinteWriter
构造函数可以接收的参数类型:
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));
FileWriter file = new FileWriter("test.txt");
PrintWriter out = new PrintWriter(new BufferedWriter(file),true);
String line = null;
while ((line = bufr.readLine())!=null)
{
if ("over".equals(line))
break;
out.println(line);
//out.flush();
}
out.close();
bufr.close();
}
}
import java.io.*;
import java.util.*;
class SplitFile
{
public static void main(String[] args) throws IOException
{
File filein = new File("Ylvis - The Fox.mp3");
splitFile(filein);
File fileout = new File("Ylvis - The Fox\\Ylvis - The Fox.mp3");
merge(fileout,"1.part","2.part","3.part","4.part");
}
//合并文件
public static void merge(File file,String... s) throws IOException
{
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for (int x = 0; x<s.length; x++)
{
al.add(new FileInputStream(s[x]));
}
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(file);
byte[] buf = new byte[1024*1024];
int len = 0;
while ((len = sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
//切割文件
public static void splitFile(File file) throws IOException
{
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = null;
byte[] buf = new byte[1024*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();
}
}
1、写入流对象:
1)创建对象写入流,与文件关联,即传入目的
2)通过写入writeObject(Object obj)方法,将对象作为参数传入,即可写入文件
2、读取流对象
1)创建对象读取流,与文件关联,即传入源
2)通过readObject()方法,读取文件中的对象,并返回这个对象
注:
1、静态成员不能被序列化
2、非静态成员要不被序列化,可以用关键字transient修饰,保证非静态成员保存在堆内存中,不能存入文件中。
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 = null;
try
{
while ((p = (Person)ois.readObject())!=null)
{System.out.println(p);}
}
catch (Exception e)
{
System.out.println("到达文件末尾");
}
ois.close();
}
public static void writeObj() throws IOException
{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
oos.writeObject(new Person("zhangsan",35));
oos.writeObject(new Person("zhangsan1",35));
oos.close();
}
}
管道流:
PipedInputStream和PipedOutputStream
特点:
a、输入输出可以直接进行连接,不用再借助数组或集合等容器进行临时存储。
b、一般结合多线程使用。通常,数据由某个线程写入PipedOutputStream对象,并由其他线程从连接的 PipedInputStream 读取。
常见操作步骤
1、要先创建一个读和写的两个类,实现Runnable接口,因为是两个不同的线程,覆盖run方法,注意,需要在内部处理异常。
2、创建两个管道流,并用connect()方法将两个流连接
3、创建读写对象,并传入两个线程内,并start执行。
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];
int len = in.read(buf);
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
{
out.write("piped lai la".getBytes());
out.close();
}
catch (IOException 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();
}
}
一、概述
1、RandomAccessFile此类的实例支持对随机访问文件的读取和写入,自身具备读写方法。
2、该类不算是IO体系中的子类,而是直接继承Object,但是它是IO包成员,因为它具备读写功能,内部封装了一个数组,且通过getFilePointer方法获取指针位置,来对数组的元素进行操作,同时可通过seek方法改变指针的位置。
3、可以完成读写的原理:内部封装了字节输入流和输出流。
4、构造函数:RandomAccessFile(File file,String mode),可已从它的构造函数中看出,该类只能操作文件(可以传入文件名字符串),而且操作文件还有模式:只读“r”、读写“rw”等四种模式。
注:如果模式为只读r,则不会创建文件,会去读一个已存在的文件,若文件不存在,则会出现异常。如果模式为读写rw,且该对象的构造函数要操作的文件不存在,会自动创建;如果存在,则不会覆盖。
特有方法
1、seek(long pos)://调整对象中指针。来进行指定位置的数据读取和写入。数据要有规律。如果设置的指针位置已有数据,写入时将会将其修改。用seek可以表示随机读写访问。
2、int skipBytes(int n):跳过指定字节数,不可往前跳
RandomAccessFile中也有对基本数据类型进行读写的方法。还有readLine方法。
使用步骤
1、创建RandomAccessFile对象
2、将数据写入到指定文件中
3、读取指定文件中的数据
注意:要单独读取后面的数据,可以使用seek方法调整指针,或skipBytes方法跳过指定字节数,这种通过改变指针位置的方式,取出相应的数据。
import java.io.*;
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();
}
}
可以用于操作基本数据类型的数据的流对象。
方法:
读
byte型 byte readbyte()
int型 intreadInt()
boolean型 boolean readBoolean()
double型 doublereadDouble()
String readUTF();//对应writeUTF,读取以UTF-8修改版编码写入的字符串
写
byte型 writeByte(int b);//将b的低八位写入
int型 writeInt(int n)
boolean型 writeBoolean(boolean b)
double型 writeDouble(double d)
writeUTF(String str);//以与机器无关方式使用UTF-8修改版编码将一个字符串写入基础输出流。
import java.io.*;
class DataStreamDemo
{
public static void main(String[] args) throws IOException
{
writeData();
readData();
writeUTFDemo();
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");
osw.write("你好");
osw.close();
readUTFDemo();
}
public static void readUTFDemo()throws IOException
{
DataInputStream dis = new DataInputStream(new FileInputStream("utf.txt"));
String s = dis.readUTF();
System.out.println(s);
dis.close();
}
public static void writeUTFDemo()throws IOException
{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("utfdate.txt"));
dos.writeUTF("你好");
dos.close();
}
public static void readData()throws IOException
{
DataInputStream dis = new DataInputStream(new FileInputStream("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("data.txt"));
dos.writeInt(234);
dos.writeBoolean(true);
dos.writeDouble(9887.543);
dos.close();
ObjectOutputStream oos = null;
oos.writeObject(new O());
}
}
概述
1、字符流的出现为了方便操作字符。
2、更重要的是加入了编码的转换,即转换流。
3、通过子类转换流来完成。在两个对象进行构造的时候,可以加入字符集(即编码表),可传入编码表的有:
1)转换流:InuputStreamReader和OutputStreamWriter
2)打印流:PrintStream和PrintWriter,只有输出流
4、编码表的由来
计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。
5、常见的编码表:
1)ASCII:美国标准信息交换码表。用一个字节的7位表示
2)IOS8859-1:拉丁码表;欧洲码表。用一个字节的8位表示
3)GB2312:中国的中文编码表()早期
4)GBK:中国的中文编码表升级,融合了更多的中文文字字符。打头的是两个高位为1的两个字节编码。为负数
5)Unicode:国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode。
6)UTF-8:最多用三个字节表示一个字符的编码表,根据字符所占内存空间不同,分别用一个、两个、三个字节来编码。
UTF-8编码格式:
一个字节:0开头
两个字节:字节一 ---> 110 位数:10 ~ 6
字节二 ---> 10 位数:5 ~ 0
三个字节:字节一 ---> 110 位数:15 ~ 12
字节二 ---> 10 位数:11 ~ 6
字节三 ---> 10 位数:5 ~ 0
转换流的编码应用
1、可以将字符以指定编码格式存储。
2、可以对文本数据指定编码格式来解读。
3、指定编码表的动作由构造函数完成。
编码和解码
1、编码:字符串变成字节数组
1)默认字符集:
String ---> byte[] :srt.getBytes()
2)指定字符集:
String ---> byte[] :srt.getBytes(charsetName)
2、解码:字节数组变成字符串
1)默认字符集:
byte[] ---> String :new String(byte[])
2)指定字符集:
byte[] ---> String :newString(byte[],charsetName)
对于编码和解码的字符集转换注意事项
1、如果编码失败,解码就没意义了。
2、如果编码成功,解码出来的是乱码,,则需对乱码通过再次编码(用解错码的编码表),然后再通过正确的编码表解码。针对于IOS8859-1是通用的。
3、如果用的是GBK编码,UTF-8解码,此时通过再次编码后解码的方式,就不能成功了,因为UTF-8也支持中文,在UTF-8解的时候,会将对应的字节数改变,所以不会成功。
如使用了错误的解码表:
4、特别注意:对于中文的”联通“,这两个字比较特别,它的二进制位正好是和在UTF-8中两个字节打头的相同,所以在文本文件中,如果单独写“联通”或者和满足UTF-8编码格式的字符一起保存时,记事本就会用UTF-8来进行解码动作,这样显示的就会是乱码。
从键盘输入以上数据。
输入的格式:张三,30,40,60计算出总成绩,
并把学生的信息和计算出的总分数高低顺序存放在磁盘文件"stud.txt"中。
步骤及思路:
2,定义一个可操作学生对象的工具类。
思想:
1,通过获取键盘录入的一行数据,并将该行数据中的信息取出,封装成学生对象
2,因为学生对象有很多,那么就需要存储,使用到集合,因为要对学生的总分排序,
所以可以使用TreeSet。
3,将集合中的信息写入到文件中。
import java.io.*;
import java.util.*;
class Student implements Comparable<Student>,Serializable
{
private String name;
int cScore,mScore,eScore;
int sumScore;
Student(String name,int cScore,int mScore,int eScore)
{
this.name = name;
this.cScore = cScore;
this.mScore = mScore;
this.eScore = eScore;
sumScore = cScore+mScore+eScore;
}
public String getName()
{
return name;
}
public int getSumScore()
{
return sumScore;
}
public int hashCode()
{
return name.hashCode()+sumScore*13;
}
public boolean equals(Object obj)
{
if (!(obj instanceof Student))
throw new ClassCastException("类型不匹配");
Student s = (Student)obj;
return this.name.equals(s.name) && this.sumScore==s.sumScore;
}
public int compareTo(Student s)
{
int num = new Integer(this.sumScore).compareTo(new Integer(s.sumScore));
if (num == 0)
return this.name.compareTo(s.name);
return num;
}
public String toString()
{
return "student["+name+","+cScore+","+mScore+","+eScore+","+sumScore+"]";
}
}
class StudentInfoTool
{
public static Set<Student> getStudents() throws IOException
{
return getStudents(null);
}
public static Set<Student> getStudents(Comparator<Student> cmp) throws IOException
{
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
Set<Student> ts = null;
if (cmp==null)
ts = new TreeSet<Student>();
else
ts = new TreeSet<Student>(cmp);
String line = null;
while ((line = bufr.readLine())!=null)
{
if ("over".equals(line))
break;
String[] s = line.split(",");
ts.add(new Student(s[0],Integer.parseInt(s[1]),Integer.parseInt(s[2]),Integer.parseInt(s[3])));
}
return ts;
}
public static void showStudents(Set<Student> stus)
{
Iterator<Student> it = stus.iterator();
while (it.hasNext())
{
System.out.println(it.next().toString());
}
}
public static void writeToFile(Set<Student> stus,File file) throws Exception
{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
Iterator<Student> it = stus.iterator();
while (it.hasNext())
{
oos.writeObject(it.next());
oos.flush();
}
oos.close();
}
public static Set<Student> readToFile(File file) throws Exception
{
return readToFile(file,null);
}
public static Set<Student> readToFile(File file,Comparator<Student> cmp) throws Exception
{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
Set<Student> stus = null;
if (cmp==null)
stus = new TreeSet<Student>();
else
stus = new TreeSet<Student>(cmp);
Student s = null;
try
{
while ((s = (Student)ois.readObject())!=null)
{
stus.add(s);
}
}
catch (Exception e)
{
}
ois.close();
return stus;
}
}
class StudentInfoTest
{
public static void main(String[] args) throws Exception
{
Comparator<Student> cmp = Collections.reverseOrder();
//Set<Student> stus = StudentInfoTool.getStudents(cmp);
//StudentInfoTool.showStudents(stus);
//StudentInfoTool.writeToFile(stus,new File("stuInfo.object"));
Set<Student> stus1 = StudentInfoTool.readToFile(new File("stuInfo.object"),cmp);
StudentInfoTool.showStudents(stus1);
}
}