Mark一下读入一行的代码

本文介绍了一个简单的字符处理程序,该程序通过逐个读取字符并统计大写字母的数量来进行字符分析。当遇到换行符时,程序会比较并记录最大计数值。
getchar();
        c=getchar();
        while(c!='\n')
        {


            if(c==' ')
                {Max=max(Max,p);p=0;}
            else
            if(c>='A'&&c<='Z')p++;
            c=getchar();
        }
6-1 学生成绩 分数 50 作者 翁恺 单位 浙江大学 要求实现一个学生成绩处理程序,程序要读入学生的成绩,然后输出成一定格式的表格。 输入数据首先是一个数字n,表明有n个学生。 然后,每个学生的数据首先是一行名字,其中可能包含空格,第二行是一个数字m,表示这个学生有m门课程的成绩。 接下去是m行,每一行有一个单词(以空格结束)和一个整数,单词是课程的名称,整数是这个学生在这门课上的成绩。 程序要读入以上格式的数据,然后产生一张表格。 表格的头(第一行)以单词“name”开头,然后是所有学生都可能有的课程名称,最后一列是单词“average”,期间以tab分隔。 从第二行开始,依次列出每一位学生的成绩,首先是他的姓名,然后是各课成绩,期间以tab分隔。如果某学生没有某门课的成绩,则在对应的位置上输出一个'-'。最后一列给出他的平均分,不带小数点后的数字。 表格的最后一行,给出每门课的平均分,但是不需要输出最后一列所有人的平均分的平均分。 函数接口定义: 请在“裁判测试程序样例”中注释的“// Your code goes here:”部分补充你的代码。 请在“裁判测试程序样例”中注释的“// Your code goes here:”部分补充你的代码。 裁判测试程序样例: #include <iostream> #include <vector> #include <set> #include <map> using namespace std; class Score { string name; int mark; public: Score():mark(0) {} Score(string _name, int _mark) : name(_name), mark(_mark) {} string getName() { return name; } int getMark() { return mark; } void scan() { cin>> name >> mark; } }; class Student { string name; map<string, int> mScore; public: string getName() { return name; } void scan(); set<string> getCourseNames(); int getMarkByCourseName(string courseName); }; class Department { vector<Student> vStudent; public: void scan() { int number; cin >> number; for ( int i=0; i<number; i++ ) { Student stu; stu.scan(); vStudent.push_back(stu); } } void report(); }; // ----- // Your code goes here: // ----- int main() { Department dept; dept.scan(); dept.report(); return 0; } /* 请在这里填写答案 */ 输入样例: 2 John Smith 3 OOP 78 JAD 82 PPL 92 Mary Johnson 2 OOP 81 Arch 67 输出样例: name Arch JAD OOP PPL average John Smith - 82 78 92 84 Mary Johnson 67 - 81 - 74 67 82 80 92 代码长度限制 16 KB 时间限制 400 ms 内存限制 64 MB
最新发布
12-26
<think>我们正在讨论Java IO流中的`mark()`和`reset()`方法,以及如何利用它们实现重复读取操作。根据引用内容,这两个方法主要用于在输入流中标记一个位置,之后可以通过`reset()`方法回到该位置重新读取数据。这在某些需要“回看”的场景中非常有用。 ### 核心概念 1. **`mark(int readlimit)`方法**:在输入流的当前位置设置一个标记。参数`readlimit`表示在标记失效前可以读取的最大字节数(或字符数)。如果读取的字节数超过了这个限制,标记可能会失效(但根据引用[1][4],在使用缓冲流时,即使超出限制,标记有时仍然有效)。 2. **`reset()`方法**:将流重置到最后一次调用`mark()`方法时的位置,允许重新读取从标记位置到当前重置位置之间的数据。 3. **支持情况**:不是所有的流都支持`mark()`和`reset()`。例如,`FileInputStream`默认不支持,而`BufferedInputStream`支持(引用[2])。我们可以通过`markSupported()`方法检查流是否支持标记操作。 ### 使用场景 - 需要重复读取一段数据(例如,解析不确定长度的数据时,先读取一部分进行判断,如果不符合条件则回退重新读取)。 - 替换文件中的特定字符串(引用[3]):标记当前位置,读取一段数据,检查是否包含目标字符串,若包含则替换并写入,否则重置到标记位置继续读取。 ### 实现步骤 1. **创建支持mark/reset的输入流**:通常使用缓冲流(如`BufferedInputStream`或`BufferedReader`)包装基础流。 2. **检查是否支持mark/reset**:调用`markSupported()`确认。 3. **设置标记**:在需要的位置调用`mark(readlimit)`,设置一个标记,并指定读取限制。 4. **读取数据**:读取一定量的数据(不超过`readlimit`,但缓冲流可能允许超出)。 5. **判断是否需要重置**:如果读取的数据不满足条件,调用`reset()`回到标记位置,然后尝试其他处理;如果满足条件,则继续读取。 6. **重置后重新读取**:从标记位置开始重新读取数据。 ### 示例代码:使用BufferedReader重复读取 以下示例展示如何使用`BufferedReader`的`mark()`和`reset()`方法重复读取一段文本: ```java import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class MarkResetExample { public static void main(String[] args) { try (BufferedReader reader = new BufferedReader(new FileReader("input.txt"))) { // 检查是否支持mark/reset if (!reader.markSupported()) { System.out.println("mark/reset not supported"); return; } // 读取第一行并标记 String line = reader.readLine(); System.out.println("Line 1: " + line); // 设置标记,参数readlimit设为100(表示我们期望在重置前最多读取100个字符) reader.mark(100); // 读取第二行 line = reader.readLine(); System.out.println("Line 2: " + line); // 重置到标记位置(即第二行开始处) reader.reset(); // 重新读取第二行 line = reader.readLine(); System.out.println("Line 2 again: " + line); // 继续读取第三行 line = reader.readLine(); System.out.println("Line 3: " + line); } catch (IOException e) { e.printStackTrace(); } } } ``` ### 注意事项 1. **`readlimit`参数**:它表示在标记失效前可以读取的字符数(或字节数)的上限。但实际中,如果使用缓冲流,即使读取超过这个限制,标记可能仍然有效(引用[1][4])。这是因为缓冲流内部已经将数据读入缓冲区,所以重置时可以从缓冲区获取数据。但为了安全起见,应尽量保守设置该值。 2. **标记位置**:调用`mark()`时,标记的是当前读取位置。之后读取的数据超过`readlimit`后,标记可能失效(此时调用`reset()`会抛出`IOException`)。 3. **流类型**:只有支持标记的流才能使用。例如: - 字节流:`BufferedInputStream`、`ByteArrayInputStream`支持。 - 字符流:`BufferedReader`、`CharArrayReader`支持。 - 而`FileInputStream`、`FileReader`等默认不支持,需要包装成缓冲流。 4. **重置次数**:只能重置到最后一次设置标记的位置,不能多次重置到不同的标记(除非再次调用`mark()`设置新标记)。 5. **资源管理**:使用`try-with-resources`确保流正确关闭。 ### 应用案例:替换文件中的字符串 引用[3]提到,可以使用`mark()`和`reset()`实现替换文件中的字符串。基本思路如下: 1. 使用`BufferedReader`读取文件,使用`BufferedWriter`写入新文件。 2. 在读取过程中,对每个可能匹配目标字符串的位置设置标记。 3. 读取一段数据(长度至少为目标字符串长度),检查是否包含目标字符串。 4. 如果包含,则重置到标记位置,然后写入替换字符串,并跳过目标字符串的长度。 5. 如果不包含,则重置到标记位置,写入当前读取的一个字符(或一小段),然后向前移动一个位置,重新设置标记。 由于实现较为复杂,且涉及边界处理,这里不展开详细代码。但核心思想就是利用`mark()`和`reset()`来回退重新读取。 ### 常见错误 - **`java.io.IOException: mark/reset not supported`**:在不支持标记的流上调用`mark()`或`reset()`(引用[2])。解决方法:使用支持标记的流(如缓冲流)包装。 - **标记失效**:读取超过`readlimit`后调用`reset()`导致标记失效。解决方法:确保读取的数据量在限制内,或使用足够大的缓冲区(如设置较大的`readlimit`)。 ### 总结 - `mark()`和`reset()`方法为Java IO提供了重复读取的能力,特别适合需要“回退”的场景。 - 使用缓冲流(如`BufferedInputStream`、`BufferedReader`)可以更可靠地支持这些操作。 - 合理设置`readlimit`参数,并注意标记的有效范围。 §§相关问题§§ 1. 如何在Java中实现文件内容的字符串替换? 2. 如何判断一个IO流是否支持mark和reset操作? 3. 使用mark/reset时有哪些常见陷阱? 4. 除了mark/reset,还有哪些方法可以实现流的重复读取?</think>### Java IO流中`mark()`与`reset()`方法的使用及重复操作实现 在Java IO流中,`mark()`和`reset()`方法提供了"标记-重置"机制,允许开发者在流中设置标记点并随时回退到该位置,从而实现流的重复读取操作。以下是关键知识点和实现方法: #### 一、核心概念解析 1. **`mark(int readlimit)`方法** - 在当前流位置设置标记点 - 参数`readlimit`:指定在标记失效前最多可读取的字节数 - 示例:`inputStream.mark(1024);` // 标记当前位置,允许后续读取1024字节 2. **`reset()`方法** - 将流重置到最后一次调用`mark()`时的位置 - 示例:`inputStream.reset();` // 回退到标记位置 3. **支持检测** 使用`markSupported()`检查流是否支持标记操作: ```java if (inputStream.markSupported()) { // 支持mark/reset操作 } ``` #### 二、实现重复操作的步骤 1. **创建支持mark/reset的流** 使用缓冲流包装基础流(如`BufferedInputStream`): ```java InputStream baseStream = new FileInputStream("data.txt"); InputStream inputStream = new BufferedInputStream(baseStream); // 支持mark/reset[^2] ``` 2. **设置标记点** 在需要重复读取的起始位置设置标记: ```java inputStream.mark(1024); // 标记当前位置,允许后续读取1024字节[^1] ``` 3. **读取数据并处理** ```java byte[] buffer = new byte[256]; int bytesRead = inputStream.read(buffer); // 处理数据... ``` 4. **重置流位置** 当需要重新处理数据时回退到标记点: ```java inputStream.reset(); // 回到mark()设置的位置[^3] ``` 5. **重复读取操作** ```java bytesRead = inputStream.read(buffer); // 重新读取相同数据 ``` #### 三、完整示例:替换文件中的字符串 ```java import java.io.*; public class StringReplacer { public static void main(String[] args) throws IOException { try (BufferedInputStream in = new BufferedInputStream(new FileInputStream("source.txt")); FileOutputStream out = new FileOutputStream("output.txt")) { if (!in.markSupported()) { throw new IOException("mark/reset not supported"); } byte[] target = "old".getBytes(); // 要替换的字符串 int matchIndex = 0; while (in.available() > 0) { in.mark(target.length); // 标记当前位置[^3] // 尝试匹配目标字符串 matchIndex = 0; while (matchIndex < target.length) { int nextByte = in.read(); if (nextByte == target[matchIndex]) { matchIndex++; } else { in.reset(); // 重置到标记位置 out.write(in.read()); // 写入不匹配的字节 break; } } // 完全匹配时执行替换 if (matchIndex == target.length) { out.write("new".getBytes()); // 写入替换内容 } } } } } ``` #### 四、关键注意事项 1. **缓冲流是必需的** - 基础流如`FileInputStream`不支持`mark/reset`,必须用`BufferedInputStream`包装[^2] - 推荐缓冲区大小 ≥ `readlimit`参数值 2. **`readlimit`参数的特殊性** - 实际可读取量可能超过`readlimit`(缓冲流会扩展能力)[^1][^4] - 但超出声明值可能导致未定义行为,应保守设置 3. **典型应用场景** - 模式匹配(如字符串替换) - 数据格式验证 - 回溯解析(如不确定长度的数据块处理) 4. **错误处理** 捕获可能的`IOException`: ```java try { inputStream.reset(); } catch (IOException e) { System.err.println("重置失败: " + e.getMessage()); } ``` #### 五、不同流类型的支持情况 | 流类型 | markSupported() | 说明 | |--------|----------------|------| | `FileInputStream` | ❌ | 需用`BufferedInputStream`包装 | | `BufferedInputStream` | ✅ | 最佳实践选择[^2][^4] | | `ByteArrayInputStream` | ✅ | 内存流支持 | | `CharArrayReader` | ✅ | 字符流支持[^5] | > **提示**:文本处理推荐使用`BufferedReader`+`mark()`/`reset()`,字符编码处理更安全[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值