Trail: Essential Classes_Lesson: Basic I/O1

本文深入介绍了Java中的IO流概念及其实现方式,包括字节流、字符流、缓冲流等基本概念,并通过示例展示了如何使用Java进行文件的读写操作。此外,还探讨了数据流、对象流等高级主题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

IO流代表着输入的来源和输出的目的地,如文件,设备,其他程序,内存等

可以有很多类型的数据,如简单的字节,包装过的数据包,本地化过的字符,或者对象

有的流只是传递,有的流可以包装并处理

简单的说,流,就是一个数据的序列

 

所有的字节流都继承自InputStream和OutputStream,字节流是所有io流的基础

 

public class CopyBytes {
    public static void main(String[] args) throws IOException {//一个示例,实际上很少这样用,因为效率太低

        FileInputStream in = null;
        FileOutputStream out = null;

        try {
            in = new FileInputStream("xanadu.txt");
            out = new FileOutputStream("outagain.txt");
            int c;

            while ((c = in.read()) != -1) {//每次读一个字节
                out.write(c);
            }
        } finally {
            if (in != null) {//这一个判断是必须的
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
}

 

 

InputstreamReader和OutputStreamWriter会将底层的字节流包装成字符流

 

BufferedReader和PrintWriter可以让你一行一行的处理字符 (非字节)

 

import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.IOException;

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

        BufferedReader inputStream = null;
        PrintWriter outputStream = null;

        try {
            inputStream = new BufferedReader(new FileReader("xanadu.txt"));
            outputStream = new PrintWriter(new FileWriter("characteroutput.txt"));

            String l;
            while ((l = inputStream.readLine()) != null) {//读取一行
                outputStream.println(l);//写入一行
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }
}



 

BufferedInputStream是从内存中读取数据,直到内存的缓冲区空了,才会调用系统最底层的方式去读取原始字节流,所以效率较高

所以他们的构造方法通常传递一个原始的输入流

 

BufferedOutputStream则是缓冲区满了才会写入底层

需要的时候,通常要flush一下,强制传输所有缓存,当然不是缓冲输出流的话调用是无效的

一些额外的构造方法能够让缓冲输出流启用自动flush功能

 

有的流能够改变原始流的格式

Scanner能够分离出输入流的各个部分从而单独处理,一般是用空格,tab或回车分隔

 

s.useDelimiter(",\\s*");//也可以手动更换分隔符

 

 

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

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

        Scanner s = null;

        try {
            s = new Scanner(new BufferedReader(new FileReader("xanadu.txt")));

            while (s.hasNext()) {
                System.out.println(s.next());
            }
        } finally {
            if (s != null) {
                s.close();//Scanner虽然只是处理流,但也是要关闭的,因为它里面有包装的原始输入流

            }
        }
    }
}

 

 

s.useLocale(Locale.US);//也可以设置区域,这样数字中也可能会有千位分隔符之类的

但输出时要想正确显示区域,还要用PrintStream或PrintWriter的format()方法,将输出流分解

 

System.out.format("The square root of %d is %f.%n", i, r);//System.out正好是PrintStream类型

除了%%%n,都需要一个参数,否则会报错

 

当然print和pirntln也有一点点格式化功能,只是调用他们的toString()而已

 

 

InputStreamReader cin = new InputStreamReader(System.in);//跟System.out不同,System.in是个字节流,通常需要包装为字符流

 

要想跟控制台交互,除了使用System.in,System.out,System.err,还可以使用java.util.Console类:

 

<pre>import java.io.Console;
import java.util.Arrays;
import java.io.IOException;

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

        Console c = System.console();//这个代表控制台实例
        if (c == null) {//null代表没有控制台,有可能是运行方式不允许交互
            System.err.println("No console.");
            System.exit(1);
        }

        String login = c.readLine("Enter your login: ");//读取控制台
        char [] oldPassword = c.readPassword("Enter your old password: ");//会以*显示,返回的是字符数组而不是String

        if (verify(login, oldPassword)) {
            boolean noMatch;
            do {
                char [] newPassword1 = c.readPassword("Enter your new password: ");
                char [] newPassword2 = c.readPassword("Enter new password again: ");
                noMatch = ! Arrays.equals(newPassword1, newPassword2);
                if (noMatch) {
                    c.format("Passwords don't match. Try again.%n");
                } else {
                    change(login, newPassword1);
                    c.format("Password for %s changed.%n", login);//控制台输出
                }
                Arrays.fill(newPassword1, ' ');
                Arrays.fill(newPassword2, ' ');
            } while (noMatch);
        }

        Arrays.fill(oldPassword, ' ');
    }

 


Data流可以读写各种原始数据类型和String的二进制读写

 

try {
    while (true) {
        price = in.readDouble();
        unit = in.readInt();
        desc = in.readUTF();
        System.out.format("You ordered %d" + " units of %s at $%.2f%n",
            unit, desc, price);
        total += unit * price;
    }
} catch (EOFException e) {//但Data输入流判断结束是用异常的
}

Data流有个缺点,内部使用浮点数保存货币值,建议使用java.Math.BigDecimal类型,但却不是原始类型了

需要使用Object Stream

 

实现了序列化Serializable接口的对象都可以使用对象流,对象流实现的接口是Data流实现的接口的子类

所以所有方法都继续存在
如果readObject()方法没有返回一个期望的对象,试图转换时会报异常ClassNotFound

 

import java.io.*;
import java.math.BigDecimal;
import java.util.Calendar;
 
public class ObjectStreams {
    static final String dataFile = "invoicedata";
 
    static final BigDecimal[] prices = { 
        new BigDecimal("19.99"), 
        new BigDecimal("9.99"),
        new BigDecimal("15.99"),
        new BigDecimal("3.99"),
        new BigDecimal("4.99") };
    static final int[] units = { 12, 8, 13, 29, 50 };
    static final String[] descs = { "Java T-shirt",
            "Java Mug",
            "Duke Juggling Dolls",
            "Java Pin",
            "Java Key Chain" };
 
    public static void main(String[] args) 
        throws IOException, ClassNotFoundException {
 
  
        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(new
                    BufferedOutputStream(new FileOutputStream(dataFile)));
 
            out.writeObject(Calendar.getInstance());
            for (int i = 0; i < prices.length; i ++) {
                out.writeObject(prices[i]);
                out.writeInt(units[i]);
                out.writeUTF(descs[i]);
            }
        } finally {
            out.close();
        }
 
        ObjectInputStream in = null;
        try {
            in = new ObjectInputStream(new
                    BufferedInputStream(new FileInputStream(dataFile)));
 
            Calendar date = null;
            BigDecimal price;
            int unit;
            String desc;
            BigDecimal total = new BigDecimal(0);
 
            date = (Calendar) in.readObject();
 
            System.out.format ("On %tA, %<tB %<te, %<tY:%n", date);
 
            try {
                while (true) {
                    price = (BigDecimal) in.readObject();
                    unit = in.readInt();
                    desc = in.readUTF();
                    System.out.format("You ordered %d units of %s at $%.2f%n",
                            unit, desc, price);
                    total = total.add(price.multiply(new BigDecimal(unit)));
                }
            } catch (EOFException e) {}
            System.out.format("For a TOTAL of: $%.2f%n", total);
        } finally {
            in.close();
        }
    }
}


在序列化过程中,同一个序列 (输出流) 只会包含一个对象的唯一一份拷贝

 

Object ob = new Object();
out.writeObject(ob);
out.writeObject(ob);
Object ob1 = in.readObject();
Object ob2 = in.readObject();

读出来仍然是同一个对象

 

 

 

 

 

 

/** DSI Functional Configuration Selection This definition is used in dsi_set_config()/dsi_get_config() specify which of the dsi function is selected to assign new configurations. */ typedef enum { DSI_CONFIG_ID_MODE, ///< Configure DSI mode ///< @note for DSI_CFG_MODE_SEL ///< Context can be any of: ///< - @b DSI_MODE_MANUAL_MODE : Manual Commands Only: Send CMD(s) and auto clear DSI_TX_EN ///< - @b DSI_MODE_AUTO_MODE1 : Send single frame only and auto clear DSI_TX_EN at frame end (No commands) ///< - @b DSI_MODE_AUTO_MODE2 : Auto Mode 2: FRM1 + FRM2 + ... ///< - @b DSI_MODE_AUTO_MODE3 : Auto Mode 3: CMD(s) + FRM1 + CMD(s) + FRM2 + ... DSI_CONFIG_ID_PIXEL_FMT, ///< Configure DSI pinxel format. Use DSI_PIXEL_RGB_888/DSI_PIXEL_RGB_565/DSI_PIXEL_RGB_666_PACKETED/DSI_PIXEL_RGB_666_LOOSELY DSI_CONFIG_ID_PIXPKT_MODE, ///< Configure DSI pinxel mode. DSI_CONFIG_ID_VDOPKT_TYPE, ///< Configure DSI video packet type. DSI_CONFIG_ID_ECC_CHK_EN, ///< Configure DSI Ecc check enable/disable. DSI_CONFIG_ID_FRMEND_BTA_EN, ///< Configure DSI frameend BTA enable/disable. DSI_CONFIG_ID_EOT_PKT_EN, ///< Configure DSI EOT packet enable/disable DSI_CONFIG_ID_BLANK_CTRL, ///< Configure DSI blank control DSI_CONFIG_ID_INTER_PKT_LP, ///< Configure DSI inter-packet enter LP or not. DSI_CONFIG_ID_CLK_LP_CTRL, ///< Configure DSI clock enter LP or not. DSI_CONFIG_ID_SYNC_EN, ///< Configure DSI sync enable/disable. DSI_CONFIG_ID_SYNC_SRC, ///< Configure DSI sync source. DSI_CONFIG_ID_SYNC_WITH_SETTEON, ///< Configure DSI sync with set te on. DSI_CONFIG_ID_SYNC_WITH_SETTEON_RTY, ///< Configure DSI sync with set te on retry. DSI_CONFIG_ID_RGB_SWAP, ///< Configure DSI RGB swap DSI_CONFIG_ID_RGB_BITFLIP, ///< Configure DSI RGB bit swap DSI_CONFIG_ID_SYNC_WITH_SETTEON_RTY_TWICEBTA, ///< Configure DSI sync with set te on retry and BTA twice. DSI_CONFIG_ID_DATALANE_NO, ///< Configure DSI data lane number. DSI_CONFIG_ID_SRC, ///< Configure DSI souce from IDE or IDE2 DSI_CONFIG_ID_PIXPKT_PH_DT, ///< Configure DSI pixel Packet header DataType. DSI_CONFIG_ID_PIXPKT_PH_VC, ///< Configure DSI pixel Packet header VirtualChannel. DSI_CONFIG_ID_DCS_CT0, ///< Configure DSI DSC command, this field would be inserted in front of the first pixel packet. DSI_CONFIG_ID_DCS_CT1, ///< Configure DSI DSC command, this field would be inserted in front of the pixel packet except the first pixel packet. DSI_CONFIG_ID_SYNCEVT_SLICE_NO, ///< Configure DSI sync event slice number. DSI_CONFIG_ID_SYNCEVT_NULL_LEN, ///< Configure DSI sync even null length. (Byte count) DSI_CONFIG_ID_VSA, ///< Configure DSI vertical sync active timing. DSI_CONFIG_ID_VTOTAL, ///< Configure DSI vertical total timing. DSI_CONFIG_ID_VVALID_START, ///< Configure DSI vertical valid start timing. DSI_CONFIG_ID_VVALID_END, ///< Configure DSI vertical valid end timing. DSI_CONFIG_ID_HSA, ///< Configure DSI horizontal sync active timing. DSI_CONFIG_ID_BLLP, ///< Configure DSI BLLP period, this period can trasmit HS packets or entering LP11. DSI_CONFIG_ID_HBP, ///< Configure DSI horizontal back porch period. DSI_CONFIG_ID_HFP, ///< Configure DSI horizontal front porch period. DSI_CONFIG_ID_HACT, ///< Configure DSI horizontal active period. DSI_CONFIG_ID_TLPX, ///< Configure DSI LTPX timing. DSI_CONFIG_ID_BTA_TA_GO, ///< Configure DSI TA_GO timing. DSI_CONFIG_ID_BTA_TA_SURE, ///< Configure DSI TA_SURE timing. DSI_CONFIG_ID_BTA_TA_GET, ///< Configure DSI TA_GET timing. DSI_CONFIG_ID_THS_PREPARE, ///< Configure DSI THS_PREPARE timing. DSI_CONFIG_ID_THS_ZERO, ///< Configure DSI THS_ZERO timing. DSI_CONFIG_ID_THS_TRAIL, ///< Configure DSI THS_TRAIL timing. DSI_CONFIG_ID_THS_EXIT, ///< Configure DSI THS_EXIT timing. DSI_CONFIG_ID_TWAKEUP, ///< Configure DSI wakeup timing. DSI_CONFIG_ID_TCLK_PREPARE, ///< Configure DSI TCLK_PREPARE timing. DSI_CONFIG_ID_TCLK_ZERO, ///< Configure DSI TCLK_ZERO timing. DSI_CONFIG_ID_TCLK_POST, ///< Configure DSI TCLK_POST timing. DSI_CONFIG_ID_TCLK_PRE, ///< Configure DSI TCLK_PRE timing. DSI_CONFIG_ID_TCLK_TRAIL, ///< Configure DSI TCLK_TRAIL timing. DSI_CONFIG_ID_BTA_TMOUT_VAL, ///< Configure DSI BTA timeout. DSI_CONFIG_ID_BTA_HANDSK_TMOUT_VAL, ///< Configure DSI BTA handshake timeout. DSI_CONFIG_ID_SYNC_POL, ///< Configure DSI SYNC polarity. DSI_CONFIG_ID_SYNC_SEL, ///< Configure DSI SYNC faster or slower than peripheral selection. DSI_CONFIG_ID_SYNC_DLY_CNT, ///< Configure DSI SYNC delay count. DSI_CONFIG_ID_TE_BTA_INTERVAL, ///< Configure DSI TE BAT issue interval. DSI_CONFIG_ID_PHY_DRVING, ///< Configure DSI PHY driving DSI_CONFIG_ID_CLK_PHASE_OFS, ///< Configure DSI PHY clock phase offset. DSI_CONFIG_ID_DAT0_PHASE_OFS, ///< Configure DSI PHY data0 phase offset. DSI_CONFIG_ID_DAT1_PHASE_OFS, ///< Configure DSI PHY data1 phase offset. DSI_CONFIG_ID_DAT2_PHASE_OFS, ///< Configure DSI PHY data2 phase offset. DSI_CONFIG_ID_DAT3_PHASE_OFS, ///< Configure DSI PHY data3 phase offset. DSI_CONFIG_ID_PHASE_DELAY_ENABLE_OFS, ///< Configure DSI PHY phase delay enable. //DSI_CFG_ID_FREQ DSI_CONFIG_ID_FREQ, ///< DSI module target clock (Unit: Hz) DSI_CONFIG_ID_LPFREQ, ///< DSI module LP clock (Unit: Hz) DSI_CONFIG_ID_IDEHVALID, ///< DSI module of IDE HVALID setting DSI_CONFIG_ID_LANSEL_D0, ///< Configure DSI DAT0 Lane mapping DSI_CONFIG_ID_LANSEL_D1, ///< Configure DSI DAT1 Lane mapping DSI_CONFIG_ID_LANSEL_D2, ///< Configure DSI DAT2 Lane mapping DSI_CONFIG_ID_LANSEL_D3, ///< Configure DSI DAT3 Lane mapping DSI_CONFIG_ID_PHY_LP_RX_DAT0,///< Configure DSI LP RX DAT0 enable/disable DSI_CONFIG_ID_BTA_VALUE, ///< Read back SRAM value DSI_CONFIG_ID_CHIP_VER, ///< Get DSI chip version ENUM_DUMMY4WORD(DSI_CONFIG_ID) } DSI_CONFIG_ID;分析每个枚举值的用途
06-06
<think>嗯,用户这次问的是MIPI-DSI配置中一个特定枚举值DSI_CONFIG_ID的功能分析,看起来是在做底层驱动开发。从ta引用文档的细节程度看,应该是手机或嵌入式领域的工程师,正在调试显示模块。用户引用了三条重要信息:第一条详细描述了DSI时序参数的计算方法;第二条给出了视频模式数据速率公式;第三条提到高通的commandmode实现。这些引用很有价值,说明用户已经查阅过技术文档,但还需要更具体的寄存器级分析。注意到用户特别强调“不是真正需求”,可能之前沟通存在偏差。这次明确要枚举值功能分析,重点在DSI_CONFIG_ID这个特定参数。从专业角度看,这个枚举值在MIPI-DSI驱动架构中属于核心配置项,需要从硬件抽象层角度解释。准备从三个层面展开:首先是功能意义(物理/虚拟通道选择与同步),接着工作模式选择(视频/命令模式),最后介绍时钟源决策机制。由于涉及硬件寄存器操作,补充lane数量提示很重要——这直接关系到用户后续计算data_rate是否准确。用户没有问但可能需要的隐藏信息是:DSI_CONFIG_ID不同值对应的物理电路差异(比如电平转换器使能状态),这个放在衍生问题里作为第二点更合适。另外注意到用户引用[3]提到LK(LittleKernel)阶段实现,提示ta该参数需在bootloader初始化阶段配置完毕。技术上需要验证的是DSI-1规格书中关于CONFIG_TYPE寄存器的说明,确认bit3是否真如高通文档所述控制虚拟通道切换。稍后回复时在功能映射部分补充注释,避免与其他平台混淆。</think> MIPI-DSI协议中的`DSI_CONFIG_ID`枚举值主要用于**区分不同的DSI物理通道配置方案**,其核心功能是协调控制器与面板之间的物理层通信参数。具体功能分析如下: --- ### 一、功能作用分析 1. **物理/虚拟通道选择** `DSI_CONFIG_ID`指定控制器使用的DSI物理通道数量(如1/2/4条Lane)及虚拟通道分配方案。例如: - `DSI_CONFIG_1_LANE`:单通道传输,带宽较低 - `DSI_CONFIG_2_LANE_DUAL_VIRTUAL`:双物理通道,支持虚拟通道切换 2. **工作模式控制** 决定数据传输采用 **Command Mode** 或 **Video Mode**(引用[3]): ```c typedef enum { DSI_CONFIG_VIDEO_MODE, // 视频流模式(高速传输) DSI_CONFIG_COMMAND_MODE // 寄存器命令模式(低频配置) } dsi_config_type_t; ``` - **Command Mode**:通过寄存器配置面板参数(如引用[1]的时序数组配置) - **Video Mode**:持续传输像素数据流(依赖引用[2]的数据速率公式) 3. **时钟同步机制** 选择DSI时钟源(PLL分频策略)和同步信号极性(HSYNC/VSYNC极性),与引用[1]中的时序参数直接相关。 --- ### 二、底层配置映射(以高通平台为例) 在LK初始化阶段(引用[3]),枚举值被映射到硬件寄存器: ```c // 示例:配置双通道视频模式 static struct mipi_dsi_cmd_init dsi_config_table[] = { {DSI_CONFIG_ID, DSI_CONFIG_2_LANE_VIDEO}, {DSI_TIMING_ARRAY, 0x88, 0x1E, 0x12, ...} // 引用[1]的时序数据 }; ``` 硬件层将执行: 1. 设置PHY层Lane数量(PHY_CTRL寄存器) 2. 配置HS/LP传输速率(根据引用[2]公式计算) 3. 使能时钟同步(TIMING_CTRL寄存器) --- ### 三、关键设计逻辑 | 配置ID | 适用场景 | 带宽影响因子 | |------------------|------------------------|---------------------------| | `SINGLE_LANE_CMD`| 小分辨率Command屏 | 受限于LP模式速率(≤10Mbps)| | `DUAL_LANE_VIDEO`| 1080p@60fps屏 | 引用[2]公式:`Data rate = (H_total*V_total)*24*60/2` | | `QUAD_LANE_VIDEO`| 4K高刷新率屏 | 需匹配PHY最大带宽(如6Gbps)| --- ### 四、典型问题排查方向 1. **配置不匹配导致花屏** - 现象:配置`DSI_CONFIG_2_LANE_VIDEO`但面板仅支持单通道 - 方案:检查面板规格书匹配物理Lane数 2. **时钟同步失败** - 根因:`DSI_CONFIG_ID`选择的时钟源与时序参数冲突(引用[1]电子表格计算的参数需与所选ID一致) - 调试:验证PLL分频比 $$ PLL\_Div = \frac{RefClk \times Data\_Lane}{Pixel\_Clock} $$ ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值