★15.I-O系统

File

相关类

示例:列出文件夹中的目录

public static void main(String[] args) {
    final String reg = "W.*";
    File path = new File("C:\\Software\\");
    String[] list = path.list(new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
            return Pattern.compile(reg).matcher(name).matches();
        }
    });
    assert list != null;
    Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
    for (String dirItem : list) {
        System.out.println(dirItem);
    }
}

InputStreamOutputStream

  • InputStream和OutputStream 面向字节 (二进制)。

InputStream

  • ByteArrayInputStream:内存缓冲区作为InputStream
  • StringBufferInputStream(弃用):String作为InputStream
  • FileInputStream:文件作为InputStream
  • PipedInputStream:管道,用于多线程
  • SequenceInputStream:组合多个InputStream
  • ObjectInputStream:用于对象序列化
  • FilterInputStream(修饰器,可同时组合多个修饰器)包含:
    • DataInputStream:其中的readLine方法已弃用
    • BufferedInputStream
    • LineNumberInputStream:针对Java编写编译器
    • PushbackInputStream:针对Java编写编译器

OutputStream

  • ByteArrayOutputStream:内存缓冲区作为OutputStream
  • FileOutputStream:文件作为OutputStream
  • PipedOutputStream:管道,用于多线程
  • ObjectOutputStream:用于对象序列化
  • FilterOutputStream(修饰器,可同时组合多个修饰器)包含:
    • DataOutputStream
    • PrintStream
    • BufferedOutputStream

Stream适配器

  • InputStreamReader:将InputStream转换成Reader。
  • OutputStreamWriter:将OutputStream转换成Writer。

注意事项

  • 要使用readLine()时,选择BufferedReader而不是DataOutputStream

ReaderWriter

  • Reader和Writer面向字符。

Reader

  • FileReader
  • StringReader
  • PipedReader:管道,用于多线程
  • CharArrayReader
  • FilterReader(修饰器,可同时组合多个修饰器)包含:
    • BufferedReader
    • LineNumberReader
    • PushbackReader

Writer

  • FileWriter
  • PrintWriter:构造器接受一个String类型文件名。
  • StringWriter
  • PipedWriter:管道,用于多线程
  • CharArrayWriter
  • FilterWriter(修饰器,可同时组合多个修饰器)包含:
    • BufferedWriter
    • PrintWriter

文件读写示例

1. 字符串 to 文件

public class BufferedInputFile {
    private static String read(String filename) throws IOException {
        BufferedReader in = new BufferedReader(new FileReader(filename));
        String s;
        StringBuilder sb = new StringBuilder();
        while ((s = in.readLine()) != null) {
            sb.append(s).append("\n");
        }
        in.close();
        return sb.toString();
    }

    public static void main(String[] args) throws IOException {
        System.out.print(read("src\\BufferedInputFile.java"));
    }
}

2. 文件 to 字符串

public class BasicFileOutput {
    public static void main(String[] args) throws IOException {
        String file = "src\\BasicFileOutput.out";
        BufferedReader in = new BufferedReader(
                new StringReader(BufferedInputFile.read("src\\BasiclileOutput.java")));
        PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)));
        int lineCount = 1;
        String s;
        while ((s = in.readLine()) != null) {
            out.println(lineCount++ + ": " + s);
        }
        out.close();
    }
}

3. 内存读写

public class MemoryInput {
    public static void main(String[] args) throws IOException {
        StringReader in = new StringReader("我是内存中的数据! ");
        int c;
        while ((c = in.read()) != -1) {
            System.out.print((char) c);
        }
    }
}

4. 格式化读写

public class StoringAndRecoveringData {
    public static void main(String[] args) throws IOException {
        DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("Data.txt")));
        out.writeDouble(3.14159);
        out.writeUTF("That was pi");
        out.writeDouble(1.41413);
        out.writeUTF("Square root of 2");
        out.close();
        DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("Data.txt")));
        System.out.println(in.readDouble());
        System.out.println(in.readUTF());
        System.out.println(in.readDouble());
        System.out.println(in.readUTF());
    }
}

5. 随机读写

public class UsineandsmAccessFile {
    private static String file = "src\\rtest.dat";

    private static void display() throws IOException {
        RandomAccessFile rf = new RandomAccessFile(file, "r");
        for (int i = 0; i < 7; i++) {
            System.out.println("Value " + i + ": " + rf.readDouble());
        }
        System.out.println(rf.readUTF());
        rf.close();
    }

    public static void main(String[] args) throws IOException {
        // 写入并输出文件
        RandomAccessFile rf = new RandomAccessFile(file, "rw");
        for (int i = 0; i < 7; i++) {
            rf.writeDouble(i * 1.414);
        }
        rf.writeUTF("The end of the file");
        rf.close();
        display();

        // 修改并输出文件
        rf = new RandomAccessFile(file, "rw");
        // 跳过5个8字节(double)的数据
        rf.seek(5 * 8);
        rf.writeDouble(333.0001);
        rf.close();
        display();
    }
}

6. 检查文件结尾

public class TestEOF {
    public static void main(String[] args) throws IOException {
        DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("src\\TestEOF.java")));
        while (in.available() != 0) {
            System.out.print((char) in.readByte());
        }
    }
}

标准I/O

主要内容

  • 标准I/O包括:System.in、System.out、System.err。
  • System类的三个重定向静态方法:setIn(InputStream)setOut(PrintStream)setErr(PrintStream)

标准I/O重定向示例

public class Redirecting {
    public static void main(String[] args) throws IOException {
        // 存储标准I/O
        InputStream sIn = System.in;
        PrintStream sOut = System.out;
        PrintStream sErr = System.err;

        BufferedInputStream in = new BufferedInputStream(new FileInputStream("src//Redirecting.java"));
        PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream("test.out")));

        // 重定向标准I/O
        System.setIn(in);
        System.setOut(out);
        System.setErr(out);

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s;
        while ((s = br.readLine()) != null) {
            System.out.println(s);
        }
        out.close();

        // 恢复标准I/O
        System.setIn(sIn);
        System.setOut(sOut);
        System.setErr(sErr);
    }
}

启动进程示例

public class OSExecute {
    public static void main(String[] args) {
        try {
            String command = "C:\\Software\\WeChat\\WeChat.exe";
            new ProcessBuilder(command.split(" ")).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

通道

简介

  • 通道可用于提高文件读写速度

简单示例

public class GetChannel {
    private static final int BSIZE = 1024;

    public static void main(String[] args) throws Exception {
        FileChannel fc = new FileOutputStream("data.txt").getChannel();
        fc.write(ByteBuffer.wrap("Some text ".getBytes()));
        fc.close();

        fc = new RandomAccessFile("data.txt", "rw").getChannel();
        fc.position(fc.size());
        fc.write(ByteBuffer.wrap("Some more".getBytes()));
        fc.close();

        fc = new FileInputStream("data.txt").getChannel();
        ByteBuffer buff = ByteBuffer.allocate(BSIZE);
        fc.read(buff);

        // 调用ByteBuffer.flip(),让ByteBuffer从写模式转变为读模式(读变写不需要调用)
        buff.flip();
        while (buff.hasRemaining()) {
            System.out.print((char) buff.get());
        }

        buff.clear();
    }
}

使用通道复制文件

方式一

public class ChannelCopy {
    private static final int BSIZE = 1024;

    public static void main(String[] args) throws Exception {
        if (args.length != 2) {
            System.out.println("arguments: sourcefile destfile");
            System.exit(1);
        }

        FileChannel in = new FileInputStream(args[0]).getChannel();
        FileChannel out = new FileOutputStream(args[1]).getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(BSIZE);
        while (in.read(buffer) != -1) {
            buffer.flip();
            out.write(buffer);
            buffer.clear();
        }
    }
}

方式二

public class TransferTo {
    public static void main(String[] args) throws Exception {
        if (args.length != 2) {
            System.out.println("arguments: sourcefile destfile");
            System.exit(1);
        }

        FileChannel in = new FileInputStream(args[0]).getChannel();
        FileChannel out = new FileOutputStream(args[1]).getChannel();
        in.transferTo(0, in.size(), out);
        // or:
        // out.transferFrom(in, 0, in.size());
    }
}

文件通道加锁

描述

  • FileChannel.tryLock():非阻塞,不一定能获取到。
  • FileChannel.lock():阻塞,阻塞直至获取到。
  • SocketChannelDatagramChannelServerSocketChannel不需要加锁。

简单示例

public class FileLocking {
    public static void main(String[] args) throws Exception {
        FileOutputStream fos = new FileOutputStream("file.txt");
        FileLock fileLock = fos.getChannel().tryLock();
        if (fileLock != null) {
            TimeUnit.MILLISECONDS.sleep(100);
            fileLock.release();
        }
        fos.close();
    }
}

字符编码

字符编解码

public class BufferToText {
    private static final int BSIZE = 1024;

    public static void main(String[] args) throws Exception {
        // 使用UTF-8编码输入(因为源代码是UTF-8)
        FileChannel fc = new FileOutputStream("data2.txt").getChannel();
        fc.write(ByteBuffer.wrap("Some text".getBytes()));
        fc.close();

        // 使用UTF-16编码输出(因为ByteBuffer.asCharBuffer()用的是Java原生编码UTF-16)
        fc = new FileInputStream("data2.txt").getChannel();
        ByteBuffer buff = ByteBuffer.allocate(BSIZE);
        fc.read(buff);
        buff.flip();
        System.out.println("1: " + buff.asCharBuffer());
        buff.rewind();

        // 使用UTF-8编码输出
        String encoding = System.getProperty("file.encoding");
        System.out.println("2: Decoded using " + encoding + ": "
                + Charset.forName(encoding).decode(buff));
        buff.clear();

        // ======================================================================
        // 使用UTF-16编码字符串
        fc = new FileOutputStream("data2.txt").getChannel();
        fc.write(ByteBuffer.wrap("Some text".getBytes("UTF-16")));
        fc.close();

        // 使用UTF-16编码输出(因为ByteBuffer.asCharBuffer()用的是Java原生编码UTF-16)
        fc = new FileInputStream("data2.txt").getChannel();
        fc.read(buff);
        buff.flip();
        System.out.println("3:" + buff.asCharBuffer());


        // ======================================================================
        // 使用UTF-16编码输入(因为ByteBuffer.asCharBuffer()用的是Java原生编码UTF-16)
        fc = new FileOutputStream("data2.txt").getChannel();
        buff = ByteBuffer.allocate(24);
        buff.asCharBuffer().put("Some text");
        fc.write(buff);
        fc.close();

        // 使用UTF-16编码输出(因为ByteBuffer.asCharBuffer()用的是Java原生编码UTF-16)
        fc = new FileInputStream("data2.txt").getChannel();
        buff.clear();
        fc.read(buff);
        buff.flip();
        System.out.println("4:" + buff.asCharBuffer());
    }
}

输出所有的字符编码

public class AvailableCharSets {
    public static void main(String[] args) {
        SortedMap<String, Charset> charSets = Charset.availableCharsets();
        for (String csName : charSets.keySet()) {
            System.out.print(csName);

            // 输出别名
            Iterator aliases = charSets.get(csName).aliases().iterator();
            if (aliases.hasNext()) {
                System.out.print(": ");
            }
            while (aliases.hasNext()) {
                System.out.print(aliases.next());
                if (aliases.hasNext()) {
                    System.out.print(", ");
                }
            }
            System.out.println();
        }
    }
}

Buffer

ByteBuffer

简单示例

public class ByteBufferDemo {
    private static final int BSIZE = 1024;

    public static void main(String[] args) {
        ByteBuffer bb = ByteBuffer.allocate(BSIZE);

        // 使用UTF-16编码
        bb.asCharBuffer().put("Howdy!");
        char c;
        while ((c = bb.getChar()) != 0) {
            System.out.print(c + " ");
        }
        System.out.println();

        bb.rewind();
        bb.asShortBuffer().put((short) 471142);
        System.out.println(bb.getShort());

        bb.rewind();
        bb.asIntBuffer().put(99471142);
        System.out.println(bb.getInt());

        bb.rewind();
        bb.asLongBuffer().put(99471142);
        System.out.println(bb.getLong());

        bb.rewind();
        bb.asFloatBuffer().put(99471142);
        System.out.println(bb.getFloat());

        bb.rewind();
        bb.asDoubleBuffer().put(99471142);
        System.out.println(bb.getDouble());
    }
}

注意事项

  • ByteBuffer分配空间的时候会自动置0。

其他Buffer

public class IntBufferDemo {
    private static final int BSIZE = 1024;

    public static void main(String[] args) {
        ByteBuffer bb = ByteBuffer.allocate(BSIZE);
        IntBuffer ib = bb.asIntBuffer();
        ib.put(new int[]{11, 42, 47, 99, 143, 811, 1016});
        // 获取索引为3的元素
        System.out.println(ib.get(3));

        // 用1811的覆盖索引为3的元素
        ib.put(3, 1811);
        ib.flip();
        while (ib.hasRemaining()) {
            int i = ib.get();
            System.out.println(i);
        }
    }
}

MappedByteBuffer

  • MappedByteBuffer:用于内存映射,可以将原来太大放不进内存的数据放进内存。
public class MappedByteBufferDemo {
    private static final int length = 100000;

    public static void main(String[] args) throws Exception {
        FileChannel fileChannel = new RandomAccessFile("test.dat", "rw").getChannel();
        MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, length);
        for (int i = 0; i < length; i++) {
            mappedByteBuffer.put((byte) 'x');
        }
        System.out.println("Finished writing");
        for (int i = length / 2; i < length / 2 + 6; i++) {
            System.out.println((char) mappedByteBuffer.get(i));
        }
    }
}

压缩

相关的类

  • CheckedInputStream:为InputStream产生校检。
  • CheckedOutputStream:为OutputStream产生校检。
  • DeflaterOutputStream:压缩类的基类。
    • ZipOutputStream:压缩为Zip格式。
    • GZIPOutputStream:压缩为GZIP格式。
  • InflaterInputStream:解压缩类的基类。
    • ZipInputStream:解压缩为Zip格式。
    • GZIPInputStream:解压缩为GZIP格式。

GZIP示例

public class GZIPCompress {
    public static void main(String[] args) throws IOException {
        if (args.length == 0) {
            System.out.println("Usage: \nGZlPcompress file\n" + "\tUses GZIP compression to compress " + "the file to test.gz");
            System.exit(1);
        }

        // 写入到GZIPOutputStream就是压缩
        BufferedReader in = new BufferedReader(new FileReader(args[0]));
        BufferedOutputStream out = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream("test.gz")));
        System.out.println("Writing file");
        int c;
        while ((c = in.read()) != -1) {
            out.write(c);
        }

        in.close();
        out.close();

        // 从GZIPOutputStream读取就是解压缩
        System.out.println("Reading file");
        BufferedReader in2 = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream("test.gz"))));
        String s;
        while ((s = in2.readLine()) != null) {
            System.out.println(s);
        }
    }
}

Zip示例

public class ZipCompress {
    public static void main(String[] args) throws IOException {
        // ============================压缩============================
        // 构建输出流
        FileOutputStream fileOut = new FileOutputStream("test.zip");
        CheckedOutputStream checkedOut = new CheckedOutputStream(fileOut, new Adler32());
        ZipOutputStream zipOut = new ZipOutputStream(checkedOut);
        BufferedOutputStream buffOut = new BufferedOutputStream(zipOut);

        // 设置zip的注释
        zipOut.setComment("A test of Java Zipping");

        // 压缩多个文件
        for (String arg : args) {
            System.out.println("Writing file " + arg);
            BufferedReader in = new BufferedReader(new FileReader(arg));
            // 每压缩一个文件调用ZipOutputStream.putNextEntry()一次
            zipOut.putNextEntry(new ZipEntry(arg));
            int c;
            while ((c = in.read()) != -1) {
                buffOut.write(c);
            }
            in.close();
            buffOut.flush();
        }
        buffOut.close();

        // 获取校检码
        System.out.println("Checksum: " + checkedOut.getChecksum().getValue());
        System.out.println();

        // ===========================解压缩===========================
        // 构建输入流
        FileInputStream fileIn = new FileInputStream("test.zip");
        CheckedInputStream checkedIn = new CheckedInputStream(fileIn, new Adler32());
        ZipInputStream zipIn = new ZipInputStream(checkedIn);
        BufferedInputStream buffIn = new BufferedInputStream(zipIn);

        FileOutputStream fileOut2 = new FileOutputStream("123.txt");

        // 获取每一个文件并解压到标准输出
        ZipEntry zipEntry;
        while ((zipEntry = zipIn.getNextEntry()) != null) {
            System.out.println("\nReading file " + zipEntry);
            int x;
            while ((x = buffIn.read()) != -1) {
                System.out.write(x);
            }
            System.out.flush();
        }
        if (args.length == 1) {
            System.out.println("\nChecksum: " + checkedIn.getChecksum().getValue());
        }
        buffIn.close();

        // 另一个获取ZipEntry的方式
        ZipFile zipFile = new ZipFile("test.zip");
        Enumeration enumeration = zipFile.entries();
        while (enumeration.hasMoreElements()) {
            ZipEntry ze2 = (ZipEntry) enumeration.nextElement();
            System.out.println("\nFile: " + ze2);
        }
    }
}

序列化

自动序列化

描述

  • 自动对象序列化条件:
    • 所有想要序列化的对象及其数据成员都要继承Serializable。
    • 对于不想要序列化的字段可以在前面加入transient关键字,将其排除。
    • 不会序列化或反序列化static字段。
  • 自动序列化对于两个对象引用指向相同内存的情况处理方式:只要它们序列化到同一个流中,还原时它们仍然会指向相同内存。

简单示例

class Worm implements Serializable {}

public class WormSerializer {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Worm worm1 = new Worm();

        // 方式1:序列化到文件
        ObjectOutputStream objOut1 = new ObjectOutputStream(new FileOutputStream("worm.out"));
        objOut1.writeObject("Worm storage\n");
        objOut1.writeObject(worm1);
        objOut1.close();

        ObjectInputStream objIn1 = new ObjectInputStream(new FileInputStream("worm.out"));
        String s1 = (String) objIn1.readObject();
        Worm worm2 = (Worm) objIn1.readObject();
        System.out.println(s1 + "w2 = " + worm2);


        // 方式2:序列化到内存(可用于对象深拷贝)
        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
        ObjectOutputStream objOut2 = new ObjectOutputStream(bytesOut);
        objOut2.writeObject("Worm storage\n");
        objOut2.writeObject(worm1);
        objOut2.flush();

        ObjectInputStream objIn2 = new ObjectInputStream(new ByteArrayInputStream(bytesOut.toByteArray()));
        String s2 = (String) objIn2.readObject();
        Worm worm3 = (Worm) objIn2.readObject();
        System.out.println(s2 + "w3 = " + worm3);
    }
}

手动序列化

描述

  • 手动对象序列化条件:
    • 要序列化的对象及其数据成员必须继承Externalizable。
    • 在Externalizable接口中的两个方法:writeExternal和readExternal中逐个成员调用writeObject和readObject。
    • 要序列化的对象的类及其数据成员必须有public默认构造函数。

简单示例

public class A implements Externalizable {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        A a = new A("A String ", 47);

        ObjectOutputStream objOut = new ObjectOutputStream(new FileOutputStream("A.out"));
        objOut.writeObject(a);
        objOut.close();

        ObjectInputStream objIn = new ObjectInputStream(new FileInputStream("A.out"));
        a = (A) objIn.readObject();
        System.out.println(a);
    }

    public A(String x, int a) {
        s = x;
        i = a;
    }

    public String toString() {
        return s + i;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(s);
        out.writeInt(i);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        s = (String) in.readObject();
        i = in.readInt();
    }

    private int i;
    private String s;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,599评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,581评论 18 399
  • 一、流的概念和作用。 流是一种有顺序的,有起点和终点的字节集合,是对数据传输的总成或抽象。即数据在两设备之间的传输...
    布鲁斯不吐丝阅读 10,018评论 2 95
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,184评论 11 349
  • 最近在项目中遇到需要自定义搜索框的问题,试了很多方法,今天才总算解决了,积累经验,总结一番。比如这种样式 代码如下
    心底碎片阅读 563评论 0 0