字符流读写数据的介绍
1.字符流
当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以ava提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。
- 因为字节流不能很好地操作本身容量单位较大的数据(一个字符有时等于多个字节),所以需要字符流。
- 如果存在那种由多个字节组成的字符,那么用字节输入流读取,则会乱码!!!但是,如果用字符输入流读取,就不会出现乱码!! 所以为了保险起见,尽量少用字节流。
1.1文件字符IO流
1.基本概念:
IO流用来处理设备之间的数据传输,java对数据的操作是通过流的方式。
文件字符IO流和文件字节IO流对应,它读入和写出的数据是以字符为单位的。
流按操作数据分:字节流和字符流
字符流的由来:其实就是字节流读取文字字节后,不直接操作,而是先查指定的编码表,获取对应的文字,再对这个文字进行操作。简单说就是:字节流+编码表
流按流向分为:输入流和输出流,相对于内存设备而言。
2.IO常用基类
字节流的抽象基类
- InputStream、OutputStream
字符流的抽象基类
- Reader、Writer
注意:这四个基类派生出的子类名称都是以其父类名作为子类名的后缀,比如:InputStream的子类FileInputStream,Reader的子类FileReader。
1.2字符和字节操作
如何简单记住字节流和字符流
- 字符流是以Reader,Writer结尾的
- 字符节流是以InputStream或OutputStream结尾的
1.3字符流读取:
字符流读取的所有类都是从Reader这个超类继承的,都是用于读取字符的,这些类分别是:
- InputSteamReader(从字符流读取)
- FileReader(继承与InputStreamReader,读取文件流)
- StringReader(读取字符串)
- PipedReader(读取管道,管道的上端来自于一个PipedWriter)
- CharArrayReader(读取字符数组)
还有两个比较特殊的类:
- FileterReader,这是个抽象类,目前只有PushbackReader类实现了它,从名字就可以看出PushbackReader类允许把读出来的数据推回流中(但能不能推到源中,还有待于验证);
- BufferedReader,这个是一个为了提高字符流读取的性能而提供的带有缓存功能的类,是一个代理类,能代理前面提到的所有类,也就是说,它可以读取所有来源的数据。
1.4字符输入流【Reader】
java.io.Reader 抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。
- public void close() : 关闭此流并释放与此流相关联的任何系统资源。
- public int read() : 从输入流读取一个字符。
- public int read(char[] cbuf) : 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中。
1.5FileReader类
java.io.FileReader 类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
小贴士:
- 字符编码: 字节与字符的对应规则。Windows系统的中文编码默认是GBK编码表。
idea中UTF-8- 字节缓冲区:一个字节数组,用来临时存储字节数据。
构造方法
- FileReader(File file) : 创建一个新的 FileReader,给定要读取的File对象。
- gileReader/Stning fileName) ·创建一个新的 FleReader 给定要速取的文件的名称。
使用字符数组读取: read(char[] cbuf),每次读取b的长度个字符到数组中,返回读取到的有效字符个数,读取到末尾时,返回 -1,代码使用演示:
package Java3;import java.io.*;public class ReaderTest2 {public static void main(String[] args) throws IOException {// 使用文件名称创建流对象FileReader fr=new FileReader("a.txt");// 定义变量,保存有效字符个数int len;// 定义字符数组,作为装字符数据的容器char[] cbuf=new char[2];// 循环读取while ((len=fr.read(cbuf))!=-1){System.out.println(new String(cbuf));}//关闭资源fr.close();}
}输出结果:
ab
cd
ed
每次读取一个字符《中文占一个字符),所有的中文字符按照一个字符处理,每次读取一个字符,把该字符转换成对应的编码值,代码演示:
package Java3;import java.io.*;
import java.util.Arrays;public class ReaderTest1 {public static void main(String[] args) throws IOException {//1.定义File对象File f1=new File("d:/a.txt");//定义字符输入流,用来读取f1这个文件Reader in=new FileReader(f1);//每次读取一个字符(中文占一个字符)int n = in.read(); //所有的中文字符按照一个字符处理,每次读取一个字符,把该字符转换成对应的编码值System.out.println((char)n);int n1=in.read();System.out.println((char)n1);}
}输出结果:
f
j
小贴士: 虽然读取了一个字符,但是会自动提升为int类型。
使用字符数组读取: in.read(buffer),使用缓冲区读取多个字符,每次最多读buffer数组长个字符,把取到的字符存入buffer数组中,返回的是实际读取到的字符数,代码演示:
package Java3;import java.io.*;
import java.util.Arrays;public class ReaderTest1 {public static void main(String[] args) throws IOException {//1.定义File对象File f1=new File("d:/a.txt");//定义字符输入流,用来读取f1这个文件Reader in=new FileReader(f1);//使用缓冲区读取多个字符char[] buffer=new char[10];int n=in.read(buffer);//每次最多读buffer数组长个字符,把取到的字符存入buffer数组中,返回的是实际读取到的字符数System.out.println(n);System.out.println(Arrays.toString(buffer));char[] buffer1=new char[10];int n1=in.read(buffer1);//每次最多读buffer数组长个字符,把取到的字符存入buffer数组中,返回的是实际读取到的字符数System.out.println(n1);System.out.println(Arrays.toString(buffer1));}
}输出结果:
10
[f, j, s, d, i, 5, 1, 6, 5, f]
4
[g, f, d, h, , , , , , ]
1.6字符输出流【Writer】
java.io.writer 抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。
- void write(int c)写入单个字符。
- void write(char[] cbuf) 写入字符数组。
- abstract void write(char[] cbuf, int off,int len) 写入字符数组的某一部分,off数组的开始索引len
写的字符个数。- void write(String str)写入字符串。
- void write(String str,int off,int len) 写入字符串的某一部分,of字符串的开始索引,len写的字符个数。
- void flush()刷新该流的缓冲。
- void close()关闭此流,但要先刷新它。
字符流Write的简单使用:代码如下:
//字符流Write的简单使用BufferedWriter bw=null;//创建BufferedWriter对象为空FileOutputStream fos=null;//创建FileOutputStream对象为空OutputStreamWriter ops=null;//创建转型对象try {fos=new FileOutputStream("a.txt");//指定写的文件ops=new OutputStreamWriter(fos,"UTF-8");//进行汉字的转换bw= new BufferedWriter(ops);//给BufferedWriter重新定义对象bw.write("第一次实验");//运用BufferedWriter类的方法进行写入bw.write("\n严伟贱说的!!");} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();//抛出异常}finally {try {bw.close();ops.close();fos.close();//关闭字节流} catch (IOException e) {e.printStackTrace();//抛出关闭异常}}
1.7 FileWriter类
java.io.Filewriter 类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
构造方法
- Filewriter(File file) : 创建一个新的 FileWriter,给定要读取的File对象。
- Filewriter(String fileName) : 创建一个新的 FileWriter,给定要读取的文件的名称。
当你创建一个流对象时,必须传入一个文件路径,类似于FileOutputStream。
package Java3;import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;public class WriterTest1 {public static void main(String[] args) throws IOException {File f2=new File("d:/b.txt");if (!f2.exists()){f2.createNewFile();}//定义一个字符输出流,向f2文件写入内容Writer out=new FileWriter(f2);out.write(97);out.write((int) '中');char[] ch={'河','南','南','阳','农','业'};out.write(ch,0,2);out.write("移动2103班");out.write("abcdef",0,3);out.flush();out.close();}
}
1.8字符流写数据的方式
字符流写数据的5中方式
方法 | 描述 |
void write(int c) | 写一个字符 |
void write(charl[] cbuf) | 写入一个字符数组 |
void write(char[] cbuf, int off, int len) | 写入字符数组的一部分 |
void write(String str) | 写一个字符串 |
void write(String str, int off, int len) | 写一个字符串的一部分 |
注意:字符流不能直接写到文件中,而是在缓冲区,需要flush;释放close,一定会把缓冲区的数据刷新一次。二者区别是调用前者还可写数据,后者一旦调用,就不能写了.
1.void write(int c); 写一个字符
public class demo {public static void main(String[] args) throws IOException {//FileInputStream fis = new FileInputStream("D:\\wkx\\shangluo");FileOutputStream fos = new FileOutputStream("D:\\wkx\\shangluo\\.chengzi.txt");OutputStreamWriter ow = new OutputStreamWriter(fos);ow.write(97);ow.flush();ow.write(98);ow.close();}
}
2.void write(char[] cbuf); 写一个字符数组
public class demo {public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("D:\\wkx\\shangluo\\.chengzi.txt");OutputStreamWriter ow = new OutputStreamWriter(fos);char [] ch ={97,98,99,100};ow.write(ch);ow.close();}
}
3.void write(char[] cbuf,int off, int len);写一个字符数组的一部分
public class demo {public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("D:\\wkx\\shangluo\\.chengzi.txt");OutputStreamWriter ow = new OutputStreamWriter(fos);char [] ch ={97,98,99,100};ow.write(ch,0,2);ow.close();}
}
4.void write(String str);写一个字符串
public class demo {public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("D:\\wkx\\shangluo\\.chengzi.txt");OutputStreamWriter ow = new OutputStreamWriter(fos);ow.write("chengzi");ow.close();}
}
5.void write(String str,int off , int len);写一个字符串的一部分
public class demo {public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("D:\\wkx\\shangluo\\.chengzi.txt");OutputStreamWriter ow = new OutputStreamWriter(fos);ow.write("chengzi",0,5);ow.close();}
}
flush方法和close方法的区别:close释放资源前进行一次刷新流,close执行后不能在写内容;而flush是刷新流,执行完毕依旧可以写内容;
字符流读数据的两种方式
方法 | 描述 |
int read() | —次读一个字符数据 |
int read(char[]cbuf) | 一次读一个字符数组数据 |
1.int read();一次读取一个字符数据
public class demo {public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("D:\\wkx\\shangluo\\.chengzi.txt");InputStreamReader ir = new InputStreamReader(fis);int ch;while ((ch=ir.read())!=-1){System.out.print((char)ch);}}
}
2.int read(char[] cbuf);一次读取一个字符数组数据
public class demo {public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("D:\\wkx\\shangluo\\.chengzi.txt");InputStreamReader ir = new InputStreamReader(fis);char [] cha = new char[1024];int len;while ((len=ir.read(cha))!=-1){System.out.print(new String (cha,0,len));}}
}
为什么读取的字符用int类型接收?
char的取值范围为0-65535,选取一个不在这个范围的数标记文件末尾,而返回-1的话需要转化到int类型
上面的方法练习
import java.io.*;public class Character {public static void main(String[] args) throws IOException {
// 字符流写数据OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("C:\\data\\writer.txt"));
// 写一个字符,结果为:dosw.write(100);
// 写入一个字符数组,结果为:defchar[] c={100,101,102};osw.write(c);
// 写入字符数组的一部分,结果为:efosw.write(c,1,2);
// 写一个字符串,结果为:落霞与孤鹜齐飞,秋水共长天一色String s="落霞与孤鹜齐飞,秋水共长天一色";osw.write(s);
// 写一个字符串的一部分,结果为:孤鹜齐飞osw.write(s,3,4);osw.close();// 字符流读数据InputStreamReader isr=new InputStreamReader(new FileInputStream("C:\\data\\将进酒.txt"),"UTF-8");
// —次读一个字符数据,这里的结果是将进酒这首诗int ch;while((ch=isr.read())!=-1){System.out.print((char)ch);}
// 一次读一个字符数组的数据,结果还是将进酒这首诗char[] cr=new char[1024];int len;while((len=isr.read(cr))!=-1){System.out.print(new String(cr,0,len));}isr.close();}
}
1.9字符流方式读写
例如把 a.txt文件内容写到b.txt文件中
- 由于我们常见的操作都是使用本地默认编码,所以,不用指定编码。
- 而转换流的名称有点长,所以,Java就提供了其子类供我们使用。
- OutputStreamWriter = FileOutputStream + 编码表(GBK)
- FileWriter = FileOutputStream + 编码表(GBK)
- InputStreamReader = FileInputStream + 编码表(GBK)
- FileReader = FileInputStream + 编码表(GBK)
需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中
数据源:
a.txt -- 读取数据 -- 字符转换流 -- InputStreamReader -- FileReader -- BufferedReader
目的地:
b.txt -- 写出数据 -- 字符转换流 -- OutputStreamWriter -- FileWriter -- BufferedWriter
2.缓冲流
昨天学习了基本的一些流,作为10流的入门,今天我们要见识一些更强大的流。比如能够高效读写的缓冲流,能够转换编码的转换流,能够持久化存储对象的序列化流等等。这些功能更为强大的流,都是在基本的流对象基础之上创建而来的,就像穿上铠甲的武士一样,相当于是对基本流对象的一种增强。
2.1概述
缓冲流,也叫高效流,是对4个基本的 Filexxx 流的增强,所以也是4个流,按照数据类型分类:
- BufferedInputStream ,BufferedOutputStream.
- 字符缓冲流: BufferedReader,Bufferedwriter.
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统I0次数,从而提高读写的效率。
2.2字节缓冲流
构造方法
- public BufferedInputstream(Inputstream in) :创建一个新的缓冲输入流。
- public Bufferedoutputstream(outputStream out): 创建一个新的缓冲输出流.
构造举例,代码如下:
// 创建字节冲输入流BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bis.txt"));// 创建字节缓冲输出流BufferedOutputStream bos = new Bufferedoutput5tream(new File0utputStream("bos.txt"));
效率测试
查询API,缓冲流读写方法与基本的流是一致的,我们通过复制大文件( 375MB),测试它的效率。
基本流,代码如下:
package Java3;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;public class BufferdTest2 {public static void main(String[] args) throws IOException {// 记录开始时间long start = System.currentTimeMillis();// 创建流对象FileInputStream fis=new FileInputStream("a.txt");FileOutputStream fos=new FileOutputStream("copy.txt");// 读写数据int b;while ((b=fis.read())!=-1){fos.write(b);}// 记录结束时间long end=System.currentTimeMillis();System.out.println("普通流复制时间:"+(end - start)+"毫秒");}
}输出结果:
普通流复制时间:1毫秒
缓冲流,代码如下:
package Java3;import java.io.*;public class BufferdTest1 {public static void main(String[] args) throws IOException {File f1=new File("D:/a.txt");File f2=new File("D:/copy.txt");BufferedReader br=new BufferedReader(new FileReader(f1));BufferedWriter bw=new BufferedWriter(new FileWriter(f2));long start = System.currentTimeMillis();int n;char[] ch=new char[10];while ((n=br.read(ch))!=-1){bw.write(ch,0,n);}long stop= System.currentTimeMillis();bw.flush();br.close();bw.close();System.out.println("缓冲流文件复制耗时:"+(stop-start));System.out.println("=============================");//使用宁符读写流定成文件复制FileReader fr=new FileReader(f1);FileWriter fw=new FileWriter(f2);long start1 = System.currentTimeMillis();int m;char[] ch1=new char[10];while ((m=fr.read(ch1))!=-1){fw.write(ch1,0,m);}long stop1 = System.currentTimeMillis();fw.flush();fr.close();fw.close();System.out.println("字符流文件复制耗时:"+(stop1-start1));}
}输出结果:
缓冲流文件复制耗时:0
=============================
字符流文件复制耗时:0
2.3字符缓冲流
BufferedReader
从字符输入流读取文本。缓冲字符,以提供字符,数组和行的高效读取。
可以指定缓冲区大小,或者可以使用默认大小。默认值足够大,可用于大多数用途。
这个类主要是提供一个其它类的代理功能,并且提供一个缓存,尤其是用在InputStream时,更能提高效率,因为他可以提前把字节流读取到缓存中,所以其他类一般都不会直接用,而是用BufferedReader包装一下再用。特别需要注意的是,这个类没有提供直接读取字节流的构造函数,也就是说它必须从字符流中读取数据。与它对应的Buffer额度Writer也是这样,只能把字符写到字符流中,而不能直接写到字节流中去。也就是说,它没有提供字符到字节的转码功能。
注意:
为了优化性能,所有的数据字符流读取类从字节流中读取数据时不是一个一个字符的数据量读的,而是一下读取很多数据,然后把这些数据放在缓存里面,再根据需求从缓存里面把字符读出来。所以,当有两个字符流读取对象对同一个block字节流进行读取时,虽然前一个字符流只读取了一个字符出来,但是因为字节的预读取,所以后一个对象可能就无法从字节流中读取数据了,如果此时后面这个对象的缓存里面也没有数据,它就会一直卡在那里,等待字节流的数据。
BufferedWriter
将文本写入字符输出流,缓冲字符、数组和字符串的高效写入
可以指定缓冲区大小,也可以接受默认大小。默认值足够大,可用于大多数用途。
构造方法
- public BufferedReader(Reader in) : 创建一个新的缓冲输入流。
- public Bufferedwriter(writer out): 创建一个新的缓冲输出流。
在关闭流的时候需要先将bw关闭,将其他抢先关闭,程序无法进行会报错。
BufferedWriter类的方法
构造举例,代码如下:
// 创建字符缓冲输入流BufferedReader br = new BufferedReader(new FileReader("br.txt"));// 创建字符缓冲输出流Bufferedwriter bw = new Bufferedwriter(new Filenriter("bw.txt"));
特有方法
字符缓冲流的基本方法与普通字符流调用方式一致,不再阐述,我们来看它们具备的特有方法。
- BufferedReader : public String readline() :读一行文字。
- BuferedWriter: public void newLine() : 写一行行分隔符,由系统属性定义符号。
read 方法演示,代码如下:
//字符流read的简单使用public static void test2(){BufferedReader br=null;//定义BufferedReader类对象为空InputStreamReader isr=null;FileInputStream fis=null;try {fis=new FileInputStream("a.txt");isr=new InputStreamReader(fis,"UTF-8");//将fis读的文件中的字体转型br=new BufferedReader(isr);//重新定义String content=null;//定义content为空while ((content= br.readLine())!=null){//读出整行内容写入content,并且判断是否为空System.out.println(content);//输出content}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {fis.close();isr.close();br.close();} catch (IOException e) {e.printStackTrace();}}}
对字符缓冲流的练习
这里用了FileReader和FileWriter是FileInputStreamReader、FileOutputStreamReader的子类,当涉及编码问题时就不能用他们了
import java.io.*;public class BufferTest {public static void main(String[] args) throws IOException {
// BufferedWriter bw=new BufferedWriter(new FileWriter("a.txt"));
// bw.write("万里悲秋常作客,百年多病独登台");
// bw.close();BufferedReader br=new BufferedReader(new FileReader("b.txt"));// readLine读取一行
// String s;
// while((s=br.readLine())!=null){
// System.out.println(s);
// }// 一次读取一个字符
// int ch;
// while((ch=br.read())!=-1){
// System.out.print((char) ch);
// }// 一次读取一个字符数组char[] c=new char[1024];int len;while((len=br.read(c))!=-1){System.out.print(new String(c,0,len));}br.close();}
}
用字符缓冲流复制文本文件
巩固
import java.io.*;public class copy {public static void main(String[] args) throws IOException {BufferedReader br=new BufferedReader(new FileReader("a.txt"));BufferedWriter bw=new BufferedWriter(new FileWriter("b.txt"));// 每次读一行有个缺点就是它不读换行符,所以会导致写出的数据全在一行
// newLine方法是写一个行分隔符(会根据系统不同写行分隔符),两个一起写出来的数据就正常了
// String s;
// while((s=br.readLine())!=null){
// bw.write(s);
// bw.newLine();
// 刷新缓冲区
// bw.flush();
// }char[] c=new char[1024];int len;while((len=br.read(c))!=-1){bw.write(c,0,len);}bw.close();br.close();}
}
注意:字符流只能操作文本文件,没法操作图片和视频的。
DataOutputStreams是数据输出流,实现八种基本类型数据的输出,该方法很便捷方便·,可以将一个盘中的大型文件很快的拷到其他地方。
未完成的结构图:
字符流读写数据的介绍相关推荐
- Java18-day09【字节缓冲流、字符流、编码表、字符串与字符流中的编码解码问题、字符流读写数据的方式、字符缓冲流、IO流小结】
视频+资料(工程源码.笔记)[链接:https://pan.baidu.com/s/1MdFNUADVSFf-lVw3SJRvtg 提取码:zjxs] Java基础--学习笔记(零起点打开java ...
- [Java基础]字符流读写数据的方式
- 在java中字符流怎么复制_Java 使用字符流拷贝数据
使用字符流拷贝数据时,需要注意在文件末尾处的数据,因为最后一次读取的长度不会刚好与数组input长度相同,所以需要引入新的变量来存储每次读取的长度. import java.io.File; impo ...
- 字符缓冲流 读写数据
字符缓冲流 读写数据 笔记 定义对象 写入数据 字符缓冲流 写数据
- Java.IO 字符流读写文件
点击上方 IT牧场 ,选择 置顶或者星标 技术干货每日送达! 一.序 上一篇我们谈了 java.IO 文件字节流读写操作(能懂系列Java.io文件字节流读写)大家应该都很熟悉了.但是中文和英文在字符 ...
- 第32天学习打卡(字符流读写文件,字节流读写文件)
字符流读写文件 创建字符流读文件对象: BufferedReader br = new BufferedReader(new FileReader("readme.txt")); ...
- Java学习第十六天——字符流读写文件、字符缓冲流拷贝文件
字符流读写文件 字符流读数据-按单个字符读取 创建字符流读文件对象: Reader reader = new FileReader("readme.txt"); 调用方法读取数 ...
- 【Java高级特性】I/O流——使用字符流读写文件
1.使用字符流类BufferedReader读文本文件 BufferedReader和InputStreamReader两个类都是Reader抽象类的子类,FileReader类是InputStrea ...
- IO流--字符流写数据
IO流是用来处理设备之间的数据传输的,诸如:文件的复制,上传下载文件 Java中的流可以从不同的角度进行分类: - 按照流的方向不同:分为输入流和输出流. - 按照处理数据单位的不同:分为字节流和字符 ...
最新文章
- OLE 操作Excel 详解(转)
- python vars 的用法
- 【Zookeeper实战】Zookeeper入门到实战看这篇就够了
- android 高德地图纠偏,高德地图纠偏算法(android ,ios)
- 硕士可以跟别的导师做实验吗_如何成为一名导师可以成为双刃剑
- Tomcat类加载器为何违背双亲委派模型
- VS2010 MFC 使用GDI+给图片添加汉字
- 请大家推荐几个快速的.net+sql server2005的虚拟主机
- IT运维服务整体方案
- 缠中说禅形态挖掘之九笔形态
- win10分辨率不能调整_WIN10屏幕分辨率不能调整的解决技巧
- Java学习总结与反思
- 图形化生物软件专题(4):MEGAN
- deepin个性化设置
- Selenium PO模式实现
- H3C服务器web怎么修改密码,h3c路由器怎么修改密码_h3c路由器找回密码
- 如何设置计算机自动连接宽带,宽带自动连接设置,小编教你电脑怎么设置宽带自动连接...
- 快速构建企业级应用的开发平台
- mysql到底是什么_MySQL数据库之MySQL到底是什么
- NCBI RefSeq命名格式的详细说明