Reading Files (File ထဲက ဒေတာကို ဖတ်ခြင်း)
B2.5.1: Construct code to perform file-processing operations: open files in read mode, read from files, close files.
မြန်မာလို: file တွေနဲ့ အလုပ်လုပ်တဲ့ code ကို ကိုယ်တိုင် ရေးနိုင်ရပါမယ်: file ကို read mode (ဖတ်ဖို့ ဖွင့်တဲ့ mode) နဲ့ ဖွင့်ခြင်း၊ file ထဲက ဖတ်ခြင်း၊ file ကို ပိတ်ခြင်း။
အဓိက အယူအဆများ
File ထဲက ဘာကြောင့် ဖတ်ရသလဲ
အခုအထိ ရေးခဲ့တဲ့ program တိုင်းက input (program ထဲ ထည့်ပေးတဲ့ ဒေတာ) ကို keyboard ကနေ ယူပြီး program ပြီးသွားတာနဲ့ ဒေတာ အားလုံး ပျောက်သွားပါတယ်။ File တွေကို သုံးရင် program က ဒါတွေကို လုပ်နိုင်ပါတယ်:
- အရင် run တုန်းက သိမ်းခဲ့တဲ့ ဒေတာကို ပြန်ယူသုံးခြင်း (ဥပမာ အမြင့်ဆုံး အမှတ်တွေ (high scores)၊ ကျောင်းသား record (အချက်အလက် အများကြီး စုထားတဲ့ ဒေတာ တစ်ခု) တွေ)
- အကြိမ်တိုင်း ရိုက်ထည့်ဖို့ မဖြစ်နိုင်လောက်အောင် ကြီးတဲ့ dataset (ဒေတာ အစုအဝေး) တွေကို ကိုင်တွယ် တွက်ချက်ခြင်း
- Configuration (program အလုပ်လုပ်ပုံကို သတ်မှတ်ထားတဲ့ အချက်တွေ) ဒါမှမဟုတ် setting တွေကို ဖတ်ခြင်း
Scanner နဲ့ ဖတ်ခြင်း
Keyboard input အတွက် သိပြီးသား Scanner class (object တွေ ဖန်တီးဖို့ ပုံစံခွက်) က file တွေကိုလည်း ဖတ်နိုင်ပါတယ်။ ကွာခြားချက် တစ်ခုတည်းက သူ့ constructor (object ဖန်တီးချိန် attribute တွေကို စတင် သတ်မှတ်ပေးတဲ့ method) ကို ဘာပေးလိုက်လဲ ဆိုတာပါပဲ။ (Python မှာ Scanner မရှိပါဘူး: open() က file object (class တစ်ခုကနေ ဖန်တီးထားတဲ့ instance) တစ်ခုကို ပေးပြီး အဲဒီ object ရဲ့ readline() method (သီးခြား အလုပ်တစ်ခု လုပ်ပေးတဲ့ code အပိုင်း) က line တစ်ကြောင်းစီ ဖတ်ပေးပါတယ်။)
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
public class ReadFile {
public static void main(String[] args) {
try {
Scanner reader = new Scanner(new File("scores.txt"));
while (reader.hasNextLine()) {
String line = reader.nextLine();
System.out.println(line);
}
reader.close();
} catch (FileNotFoundException e) {
System.out.println("Error: file not found.");
}
}
}
try:
f = open("scores.txt", "r")
line = f.readline()
while line != "": # readline() returns "" at end of file
print(line.rstrip("\n")) # readline() keeps the newline - remove it so the output matches
line = f.readline()
f.close()
except FileNotFoundError:
print("Error: file not found.")
အဓိက အချက်များ:
new File("scores.txt")က file ကို ညွှန်းတဲ့ File object တစ်ခုကို ဖန်တီးပါတယ်reader.hasNextLine()က ဖတ်စရာ line ကျန်သေးသရွေ့trueကို return (ရလဒ်အဖြစ် ပြန်ပေး) လုပ်ပါတယ်reader.nextLine()က နောက် line ကို ဖတ်ပြီး String (စာသား) အဖြစ် return လုပ်ပါတယ်reader.close()က file resource (program က ယူသုံးထားတဲ့ ကွန်ပျူတာရဲ့ အရင်းအမြစ်) ကို ပြန်လွှတ်ပေးပါတယ်try/catchက file မရှိတဲ့ အခြေအနေကို ကိုင်တွယ်ပါတယ်
ဖတ်ပြီးရင် file ကို အမြဲ ပိတ်ပါ။ မပိတ်ရင် file handle (program နဲ့ ဖွင့်ထားတဲ့ file ကြားက ချိတ်ဆက်မှု) က ဖွင့်လျက် ကျန်နေပြီး တခြား code က အဲဒီ file ကို သုံးဖို့ ကြိုးစားတဲ့အခါ ပြဿနာ ဖြစ်နိုင်ပါတယ်။
ဒေတာကို ဖတ်ပြီး parse လုပ်ခြင်း
File အများစုမှာ parse (အဓိပ္ပာယ်ရှိတဲ့ အပိုင်းတွေအဖြစ် ခွဲထုတ်) လုပ်ဖို့ လိုတဲ့ ဖွဲ့စည်းပုံရှိတဲ့ ဒေတာ (structured data) တွေ ပါပါတယ်။
File: students.csv
Alice,85
Bob,72
Charlie,91
try {
Scanner reader = new Scanner(new File("students.csv"));
int total = 0;
int count = 0;
while (reader.hasNextLine()) {
String line = reader.nextLine();
String[] parts = line.split(",");
String name = parts[0];
int score = Integer.parseInt(parts[1].trim());
System.out.println(name + " scored " + score);
total += score;
count++;
}
reader.close();
if (count > 0) {
System.out.println("Average: " + (double) total / count);
}
} catch (FileNotFoundException e) {
System.out.println("File not found.");
}
try:
f = open("students.csv", "r")
total = 0
count = 0
line = f.readline()
while line != "":
parts = line.split(",")
name = parts[0]
score = int(parts[1].strip()) # strip() also removes the newline readline() keeps
print(name, "scored", score)
total = total + score
count = count + 1
line = f.readline()
f.close()
if count > 0:
print("Average:", total / count) # / always gives a decimal in Python - no cast needed
except FileNotFoundError:
print("File not found.")
Output (program က ထုတ်ပြတဲ့ ရလဒ်):
Alice scored 85
Bob scored 72
Charlie scored 91
Average: 82.66666666666667
BufferedReader နဲ့ ဖတ်ခြင်း
BufferedReader (file ကို ထိရောက်စွာ ဖတ်တဲ့ Java class) က readLine() နဲ့ line တစ်ကြောင်းလုံးကို ပေးပြီး parsing ဘာမှ မလုပ်ပါဘူး (ခွဲခြင်း၊ type ပြောင်းခြင်း မလုပ်ပါ)။ ဒါကြောင့် ရှည်လျားတဲ့ file ကို line တစ်ကြောင်းချင်း ဖတ်ဖို့ သင့်တော်ပါတယ်။ Scanner ကတော့ ဖတ်ရင်းနဲ့ ခွဲပြီး type ပြောင်းပေးပါတယ် (nextInt(), nextDouble())။ ဒါက data type (ဒေတာ အမျိုးအစား) ရောနေတဲ့ ဒေတာအတွက် အသုံးဝင်ပေမယ့် item (အချက်) တစ်ခုစီအတွက် အလုပ် နည်းနည်း ပိုလုပ်ရပါတယ်။
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
try {
BufferedReader reader = new BufferedReader(new FileReader("scores.txt"));
String line = reader.readLine();
while (line != null) {
System.out.println(line);
line = reader.readLine();
}
reader.close();
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
# Python has no separate BufferedReader - open() already buffers for you.
# The loop shape is the same: a priming read, then read again at the end of the body.
# One difference: readline() returns "" (an empty string) at end of file, not None.
try:
f = open("scores.txt", "r")
line = f.readline()
while line != "":
print(line.rstrip("\n")) # readline() keeps the newline - remove it so the output matches
line = f.readline()
f.close()
except OSError: # the twin of Java's IOException: covers a missing file and other read errors
print("Error reading file.")
Scanner နဲ့ ကွာခြားချက်များ:
readLine()က end-of-file (file ရဲ့ အဆုံး) ရောက်ရင်null(ဘာ object ကိုမှ မညွှန်းတဲ့ တန်ဖိုး) ကို return လုပ်ပါတယ် (boolean (true ဒါမှမဟုတ် false တန်ဖိုးပဲ ယူတဲ့) စစ်ချက် မဟုတ်ပါ)IOExceptionကို catch လုပ်ပါတယ် (FileNotFoundExceptionထက် ပိုကျယ်ပါတယ်)- Parsing မလုပ်လို့ ရှည်တဲ့ file တွေကို line တစ်ကြောင်းချင်း ဖတ်ဖို့ သင့်တော်ပါတယ်
| Class | အသင့်တော်ဆုံး | End-of-File အချက်ပြ |
|---|---|---|
Scanner(File) | File အသေးတွေ၊ type ရောနေတဲ့ ဒေတာ | hasNextLine() က false ကို return လုပ်ပါတယ် |
BufferedReader | File အကြီးတွေ၊ line တစ်ကြောင်းချင်း ဖတ်ခြင်း | readLine() က null ကို return လုပ်ပါတယ် |
try-with-resources (file ကို အလိုအလျောက် ပိတ်ပေးတဲ့ try ပုံစံ)
Java ရဲ့ try-with-resources syntax (code ရေးထုံး) က exception (program run နေစဉ် ဖြစ်တဲ့ အမှား) ဖြစ်ခဲ့ရင်တောင် file ကို အလိုအလျောက် ပိတ်ပေးပါတယ်:
try (Scanner reader = new Scanner(new File("data.txt"))) {
while (reader.hasNextLine()) {
System.out.println(reader.nextLine());
}
} // reader is automatically closed here
ဒါက finally block ထဲမှာ close() ကို ကိုယ်တိုင် ခေါ်တာထက် ပိုသပ်ရပ်ပါတယ်။ (Python မှာလည်း အလားတူ အတိုကောက် နည်းလမ်း with statement (code ထဲက ညွှန်ကြားချက်) ရှိပါတယ်၊ ဒါပေမယ့် IB Python (IB Computer Science သင်ရိုးမှာ သုံးတဲ့ Python ရေးပုံ) က open() နဲ့ close() ကို တိုက်ရိုက် ရေးပြီး သုံးလို့ ဒီ site မှာလည်း အဲဒီအတိုင်း သုံးပါတယ်။)
အဆင့်ဆင့် ရှင်းပြထားတဲ့ ဥပမာများ
ဥပမာ 1: File ထဲက line အရေအတွက်ကို ရေတွက်ခြင်း
public static int countLines(String filename) throws FileNotFoundException {
Scanner reader = new Scanner(new File(filename));
int count = 0;
while (reader.hasNextLine()) {
reader.nextLine();
count++;
}
reader.close();
return count;
}
def count_lines(filename):
f = open(filename, "r")
count = 0
line = f.readline()
while line != "":
count = count + 1
line = f.readline()
f.close()
return count
ဥပမာ 2: အကြီးဆုံး တန်ဖိုးကို ရှာခြင်း
Integer (ကိန်းပြည့်) တွေ ပါတဲ့ file (line တစ်ကြောင်းမှာ တစ်ခု) ကို ဖတ်ပြီး အကြီးဆုံးကို ရှာပါ။
public static int findMax(String filename) throws FileNotFoundException {
Scanner reader = new Scanner(new File(filename));
int max = Integer.parseInt(reader.nextLine().trim()); // start from the first value
while (reader.hasNextLine()) {
int value = Integer.parseInt(reader.nextLine().trim());
if (value > max) {
max = value;
}
}
reader.close();
return max;
}
def find_max(filename):
f = open(filename, "r")
largest = int(f.readline().strip()) # start from the first value
# (named largest, not max, because max() is a built-in function)
line = f.readline()
while line != "":
value = int(line.strip())
if value > largest:
largest = value
line = f.readline()
f.close()
return largest
Version နှစ်ခုလုံးက file ထဲက ပထမ တန်ဖိုးကနေ စတာကြောင့် file မှာ အနည်းဆုံး line တစ်ကြောင်း ရှိရပါမယ်။ File အလွတ် ဖြစ်နေရင် ပထမ တန်ဖိုး မရှိပါဘူး: Java ရဲ့ nextLine() က NoSuchElementException ကို throw လုပ်ပြီး Python ရဲ့ int("") က ValueError ကို raise လုပ်ပါတယ် (throw နဲ့ raise နှစ်ခုလုံးက exception ဖြစ်ကြောင်း အချက်ပြတာကို ဆိုလိုပါတယ်)။
ဥပမာ 3: ArrayList ထဲကို ဖတ်ထည့်ခြင်း
File မှာ line ဘယ်နှစ်ကြောင်း ရှိလဲ မသိတဲ့အခါ ArrayList (ကြီးလာ၊ သေးသွားနိုင်တဲ့ list) ထဲကို ဖတ်ထည့်ပါ။
public static ArrayList<String> readAllLines(String filename) throws FileNotFoundException {
ArrayList<String> lines = new ArrayList<>();
Scanner reader = new Scanner(new File(filename));
while (reader.hasNextLine()) {
lines.add(reader.nextLine());
}
reader.close();
return lines;
}
def read_all_lines(filename):
lines = [] # a plain Python list grows as needed - no ArrayList required
f = open(filename, "r")
line = f.readline()
while line != "":
lines.append(line.rstrip("\n")) # store the line without its newline, like nextLine() does
line = f.readline()
f.close()
return lines
Error တွေကို သင့်တော်အောင် ကိုင်တွယ်ခြင်း
File မရှိတဲ့အခါ
File file = new File("data.txt");
if (!file.exists()) {
System.out.println("File does not exist. Starting with empty data.");
return new ArrayList<>();
}
// ... proceed to read
# Python has no File object - check by trying to open the file.
# (Shown inside a function, like the Java version, so return works.)
def load_data():
try:
f = open("data.txt", "r")
except FileNotFoundError:
print("File does not exist. Starting with empty data.")
return []
# ... proceed to read
ပျက်နေတဲ့ ဒေတာ
Parse လုပ်လို့ မရတဲ့ line တွေမှာ program ကို crash (program ရုတ်တရက် ပျက်ပြီး ရပ်သွားခြင်း) မဖြစ်စေဘဲ အဲဒီ line တွေကို ကျော်သွားပါ:
while (reader.hasNextLine()) {
String line = reader.nextLine();
try {
String[] parts = line.split(",");
String name = parts[0].trim();
int score = Integer.parseInt(parts[1].trim());
students.add(new Student(name, score));
} catch (NumberFormatException e) {
System.out.println("Skipping invalid line: " + line);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Skipping malformed line: " + line);
}
}
line = f.readline()
while line != "":
try:
parts = line.split(",")
name = parts[0].strip()
score = int(parts[1].strip())
students.append(Student(name, score))
except ValueError: # int() failed - the score was not a number
print("Skipping invalid line:", line.rstrip("\n"))
except IndexError: # no comma on the line, so parts[1] does not exist
print("Skipping malformed line:", line.rstrip("\n"))
line = f.readline()
Quick Check (အမြန် စစ်ဆေးမေးခွန်း)
Q1. File ရဲ့ အဆုံးကို ရောက်တဲ့အခါ reader.hasNextLine() က ဘာကို return လုပ်သလဲ။
Q2. BufferedReader က file ရဲ့ အဆုံးကို ဘယ်လို အချက်ပြသလဲ။
Q3. File တစ်ခုမှာ line တစ်ကြောင်းကို record တစ်ခုစီ name,score ပုံစံနဲ့ သိမ်းထားပါတယ်၊ ဥပမာ "Alice,85" နဲ့ "Bartholomew,92"။ Line တစ်ကြောင်းစီကနေ နာမည်နဲ့ အမှတ်ကို ဘယ်လို ခွဲထုတ်မလဲ။
Q4. မရှိတဲ့ file ကို ဖတ်ဖို့ ကြိုးစားရင် ဘယ် exception ကို throw လုပ်သလဲ။
Q5. File ကို ဖတ်ပြီးတဲ့အခါ reader.close() ကို ခေါ်ဖို့ ဘာကြောင့် အရေးကြီးသလဲ။
Code Completion (code ကွက်လပ် ဖြည့်ခြင်း)
File တစ်ခုကို ဖတ်ပြီး integer အားလုံးရဲ့ ပေါင်းလဒ်ကို return လုပ်ပေးတဲ့ method ကို ပြည့်စုံအောင် ဖြည့်ပါ။
ကွက်လပ် ဖြည့်ပါ: line တစ်ကြောင်းမှာ integer တစ်ခုစီ ပါတဲ့ file ကနေ integer တွေကို ဖတ်ပါ။
public static int sumFromFile(String filename) throws FileNotFoundException {
Scanner reader = new Scanner(new (filename));
int total = 0;
while (reader.) {
total += Integer.parseInt(reader..trim());
}
reader.;
return total;
} Spot the Error (အမှား ရှာခြင်း)
ဒီ code က line အားလုံးကို ဖတ်ရမှာပါ၊ ဒါပေမယ့် line တွေကို တစ်ကြောင်းခြားစီပဲ ဖတ်ပါတယ်။
အမှား ရှာပါ: ဒီ code က line တိုင်းကို print ထုတ်ရမှာပါ၊ ဒါပေမယ့် line တွေကို တစ်ကြောင်းခြားစီ ကျော်သွားပါတယ်။
မှန်ကန်တဲ့ ပြင်နည်းကို ရွေးပါ:
Predict the Output (output ကို ကြိုခန့်မှန်းခြင်း)
ကြိုခန့်မှန်းပါ: students.csv file ထဲမှာ Alice,85 / Bob,72 / Charlie,91 ဆိုတဲ့ line တွေ ပါရင် ဒီ code က ဘာကို print ထုတ်မလဲ။
Scanner reader = new Scanner(new File("students.csv"));
while (reader.hasNextLine()) {
String[] parts = reader.nextLine().split(",");
System.out.println(parts[0]);
}
reader.close(); Practice Exercises (လေ့ကျင့်ခန်းများ)
Core (အခြေခံ အဆင့်)
-
ဖတ်ပြီး ရေတွက်ခြင်း:
numbers.txt(line တစ်ကြောင်းမှာ integer တစ်ခု) ထဲက integer တွေကို ဖတ်ပြီး ပေါင်းလဒ်၊ အရေအတွက်နဲ့ ပျမ်းမျှကို print ထုတ်တဲ့ program ကို ရေးပါ။ -
ArrayList ထဲကို ဖတ်ထည့်ခြင်း:
names.txtထဲက line အားလုံးကိုArrayList<String>ထဲကို ဖတ်ထည့်ပါ။ နာမည် စုစုပေါင်း အရေအတွက်နဲ့ list ထဲက နောက်ဆုံး နာမည်ကို print ထုတ်ပါ။ -
CSV parser (CSV ကို parse လုပ်ပေးတဲ့ program): Line တစ်ကြောင်းစီက
name,priceပုံစံ ဖြစ်တဲ့ CSV (comma နဲ့ ခြားထားတဲ့ စာသား file) fileproducts.csvကို ဖတ်ပါ (ဥပမာKeyboard,79.99)။ Product တစ်ခုစီနဲ့ သူ့ စျေးနှုန်းကို print ထုတ်ပါ။ မမှန်ကန်တဲ့ ဒေတာ ပါတဲ့ line တွေကို ကျော်သွားအောင် ကိုင်တွယ်ပါ။
Extension (တိုးချဲ့ အဆင့်)
-
File ထဲမှာ ရှာခြင်း: File တစ်ခုကို line တစ်ကြောင်းချင်း ဖတ်ပြီး
targetပထမဆုံး ပေါ်တဲ့ line နံပါတ် (1 ကနေ စရေတွက်တဲ့ နံပါတ်) ကို return လုပ်ပေးတဲ့findInFile(String filename, String target)method ကို ရေးပါ။ မတွေ့ရင် -1 ကို return လုပ်ပါ။ တိုက်စစ်ဖို့.contains()ကို သုံးပါ။ -
File စာရင်းအင်း: Text file (စာသားပဲ ပါတဲ့ file) တစ်ခုကို ဖတ်ပြီး line စုစုပေါင်း၊ စကားလုံး စုစုပေါင်း၊ character စုစုပေါင်းနဲ့ အရှည်ဆုံး line ကို ထုတ်ပြပါ။
Challenge (စိန်ခေါ်မှု အဆင့်)
- File နှစ်ခုကို ပေါင်းခြင်း: Sorted (တန်ဖိုးအလိုက် အစဉ်တကျ စီပြီးသား) integer file နှစ်ခု (
sorted1.txtနဲ့sorted2.txt၊ line တစ်ကြောင်းမှာ တစ်ခု) ကို ဖတ်ပြီး integer အားလုံးကို အစဉ်တကျ စီထားတဲ့ တတိယ filemerged.txtကို ထုတ်ပါ။ File နှစ်ခုလုံးကို memory (မှတ်ဉာဏ်) ထဲ တစ်ပြိုင်နက် မထည့်ပါနဲ့: file တစ်ခုစီကနေ line တစ်ကြောင်းစီ ဖတ်ပါ။
ဆက်စပ် ခေါင်းစဉ်များ
- အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: Exception Handling (Exception တွေကို ကိုင်တွယ်ခြင်း): file error တွေအတွက် try/catch
- အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: ArrayList: line အရေအတွက် မသိတဲ့ file တွေကို ကြီးလာ၊ သေးသွားနိုင်တဲ့ list ထဲ ဖတ်ထည့်ခြင်း
- အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: Strings:
.split()၊.trim()၊ parse လုပ်ခြင်း - ဆက်စပ် ခေါင်းစဉ်: Writing Files (file ထဲကို ဒေတာ ရေးခြင်း): ဖတ်ခြင်းရဲ့ အတွဲဖက်ဖြစ်တဲ့ output ဘက်ခြမ်း
- နောက်ထပ် လေ့လာမယ့် ခေါင်းစဉ်: File I/O in Apps (app တွေထဲမှာ file ဖတ်ခြင်း၊ ရေးခြင်း): JavaFX (Java နဲ့ desktop app တည်ဆောက်တဲ့ library) application တွေထဲမှာ file တွေကို ဖတ်ခြင်း