Spring Batch হলো স্প্রিং ফ্রেমওয়ার্কের একটি শক্তিশালী মডিউল, যা বড় আকারের ডেটা প্রসেসিং কার্যক্রমের জন্য ডিজাইন করা হয়েছে। এটি ব্যাচ জব (Batch Job) চালানোর জন্য নির্ভরযোগ্য, স্কেলেবল এবং পুনরায় ব্যবহারযোগ্য উপায় প্রদান করে।
Spring Batch একটি ফ্রেমওয়ার্ক, যা ডেটা-প্রসেসিং জবগুলি চালানোর জন্য ব্যবহৃত হয়। এটি পড়া (Read), প্রক্রিয়াকরণ (Process) এবং লেখা (Write) প্যাটার্নে কাজ করে। Spring Batch বড় আকারের ডেটা প্রক্রিয়াকরণ, ট্রানজেকশন ম্যানেজমেন্ট, রিস্টার্টেবল জব, এবং প্যারালাল প্রসেসিং সমর্থন করে।
একটি ব্যাচ প্রসেসিং কাজের পূর্ণ বিবরণ। এটি এক বা একাধিক স্টেপ (Step) নিয়ে গঠিত।
একটি জব-এর নির্দিষ্ট অংশ, যা Tasklet বা Chunk ভিত্তিক হয়। প্রতিটি স্টেপ একক কাজ সম্পন্ন করে।
ডেটা সোর্স থেকে ডেটা পড়ার দায়িত্ব পালন করে। উদাহরণ: FlatFileItemReader, JdbcCursorItemReader।
রিডার থেকে প্রাপ্ত ডেটা প্রক্রিয়াকরণ করে। উদাহরণ: ডেটা ফিল্টারিং, ট্রান্সফরমেশন।
ডেটা ডেস্টিনেশনে লেখার দায়িত্ব পালন করে। উদাহরণ: FlatFileItemWriter, JdbcBatchItemWriter।
Spring Batch তিনটি প্রধান ধাপে কাজ করে:
Spring Batch ব্যবহারের জন্য spring-boot-starter-batch
ডিপেনডেন্সি যুক্ত করতে হবে।
pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
উদাহরণ:
@Configuration
@EnableBatchProcessing
public class BatchConfig {
@Bean
public FlatFileItemReader<String> reader() {
FlatFileItemReader<String> reader = new FlatFileItemReader<>();
reader.setResource(new ClassPathResource("input.txt"));
reader.setLineMapper((line, lineNumber) -> line); // Simple line mapping
return reader;
}
@Bean
public ItemProcessor<String, String> processor() {
return item -> item.toUpperCase(); // Convert to uppercase
}
@Bean
public FlatFileItemWriter<String> writer() {
FlatFileItemWriter<String> writer = new FlatFileItemWriter<>();
writer.setResource(new FileSystemResource("output.txt"));
writer.setLineAggregator(new PassThroughLineAggregator<>());
return writer;
}
@Bean
public Step step1(StepBuilderFactory stepBuilderFactory, FlatFileItemReader<String> reader,
ItemProcessor<String, String> processor, FlatFileItemWriter<String> writer) {
return stepBuilderFactory.get("step1")
.<String, String>chunk(10)
.reader(reader)
.processor(processor)
.writer(writer)
.build();
}
@Bean
public Job job(JobBuilderFactory jobBuilderFactory, Step step1) {
return jobBuilderFactory.get("job1")
.incrementer(new RunIdIncrementer())
.start(step1)
.build();
}
}
input.txt
):apple
banana
cherry
output.txt
):APPLE
BANANA
CHERRY
[Reader] ---> [Processor] ---> [Writer]
প্রতিটি স্টেপ নির্দিষ্ট কাজ সম্পন্ন করে এবং জবটি সম্পূর্ণ হওয়ার আগে সমস্ত স্টেপ একত্রে কাজ করে।
Spring Batch একটি শক্তিশালী টুল যা বড় আকারের ডেটা প্রসেসিং কার্যক্রমকে আরও দক্ষ এবং সংগঠিত করে তোলে। এটি ডেটা প্রসেসিং সিস্টেমের জন্য আদর্শ এবং পুনঃব্যবহারযোগ্য সমাধান প্রদান করে।
Spring Batch একটি ওপেন সোর্স, উচ্চক্ষমতাসম্পন্ন ফ্রেমওয়ার্ক যা batch processing এর জন্য ডিজাইন করা হয়েছে। এটি বিশেষভাবে বড় পরিমাণে ডেটা প্রক্রিয়াকরণের জন্য ব্যবহৃত হয়, যেমন বড় ডেটাসেটের ইনপুট, প্রক্রিয়াকরণ এবং আউটপুট। Spring Batch এর মাধ্যমে আপনি দ্রুত এবং দক্ষভাবে ETL (Extract, Transform, Load) অপারেশন করতে পারবেন।
Spring Batch প্রধানত business applications-এ ব্যবহৃত হয় যেখানে ডেটা একটি নির্দিষ্ট প্রক্রিয়া অনুসরণ করে বিশ্লেষণ করা, ফিল্টার করা বা ফরম্যাট করা হয়। এতে রয়েছে job processing, error handling, transaction management, reporting, এবং logging এর জন্য প্রয়োজনীয় টুলস।
Spring Batch মূলত কিছু গুরুত্বপূর্ণ উপাদান দিয়ে গঠিত যা batch job প্রসেসিং করতে ব্যবহৃত হয়:
Spring Batch প্রধানত বড় ডেটাসেটের প্রক্রিয়াকরণ এবং ETL (Extract, Transform, Load) কাজগুলির জন্য ব্যবহৃত হয়। এখানে কিছু practical use cases দেওয়া হল:
ধরা যাক, আমাদের একটি সিম্পল Spring Batch job তৈরি করতে হবে যা একটি CSV ফাইল থেকে ডেটা পড়ে এবং তা database-এ ইনসার্ট করে।
package com.example.config;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.scope.context.JobExecutionContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.transform.DefaultLineMapper;
import org.springframework.batch.item.file.transform.LineTokenizer;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.batch.item.support.ListItemWriter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.JdbcTemplate;
@Configuration
@EnableBatchProcessing
public class BatchConfig {
@Bean
public FlatFileItemReader<User> reader() {
FlatFileItemReader<User> reader = new FlatFileItemReader<>();
reader.setResource(new ClassPathResource("users.csv"));
reader.setLineMapper(new DefaultLineMapper<>() {{
setLineTokenizer(new DelimitedLineTokenizer() {{
setNames("id", "name", "email");
}});
setFieldSetMapper(new BeanWrapperFieldSetMapper<>() {{
setTargetType(User.class);
}});
}});
return reader;
}
@Bean
public ListItemWriter<User> writer() {
return new ListItemWriter<>();
}
@Bean
public Step step1(StepBuilderFactory stepBuilderFactory) {
return stepBuilderFactory.get("step1")
.<User, User>chunk(10)
.reader(reader())
.processor(new UserProcessor())
.writer(writer())
.build();
}
@Bean
public Job job(JobBuilderFactory jobBuilderFactory, Step step1) {
return jobBuilderFactory.get("job1")
.incrementer(new RunIdIncrementer())
.flow(step1)
.end()
.build();
}
@Bean
public JobLauncher jobLauncher(JobLauncher jobLauncher) {
return jobLauncher;
}
}
ব্যাখ্যা:
CSV
ফাইল থেকে ডেটা পড়া হয়।package com.example.processor;
import org.springframework.batch.item.ItemProcessor;
import com.example.model.User;
public class UserProcessor implements ItemProcessor<User, User> {
@Override
public User process(User item) throws Exception {
// Example of transforming data before writing to database
item.setName(item.getName().toUpperCase());
return item;
}
}
ব্যাখ্যা:
package com.example.model;
public class User {
private Long id;
private String name;
private String email;
// getters and setters
}
1,John Doe,john.doe@example.com
2,Jane Smith,jane.smith@example.com
package com.example;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class BatchApplication {
public static void main(String[] args) {
SpringApplication.run(BatchApplication.class, args);
}
@Bean
public CommandLineRunner run(JobLauncher jobLauncher, Job job) {
return args -> {
jobLauncher.run(job, new JobParameters());
};
}
}
Spring Batch একটি শক্তিশালী ফ্রেমওয়ার্ক যা বৃহৎ আকারের ডেটা প্রক্রিয়াকরণ, ETL অপারেশন এবং ব্যাচ প্রসেসিং সহজ এবং দক্ষভাবে পরিচালনা করতে ব্যবহৃত হয়। এটি ItemReader, ItemProcessor, ItemWriter, Job এবং Step ব্যবহারের মাধ্যমে ডেটা এক্সট্র্যাকশন, ট্রান্সফরমেশন এবং লোডিং প্রক্রিয়াগুলিকে মডুলার এবং স্কেলেবল করে তোলে। Spring Batch
Spring Batch হল স্প্রিং ফ্রেমওয়ার্কের একটি গুরুত্বপূর্ণ কম্পোনেন্ট যা বড় পরিমাণ ডেটা প্রসেসিং এবং ব্যাচ টাস্কের জন্য ব্যবহৃত হয়। এটি Job, Step, এবং Tasklet এর মতো মৌলিক উপাদান দিয়ে তৈরি, যা ডেটা প্রক্রিয়া এবং ব্যাচ প্রসেসিংয়ের কাজ সহজ এবং কার্যকর করে তোলে।
এই টিউটোরিয়ালে আমরা Spring Batch এর মূল উপাদানগুলি — Job, Step, Tasklet এবং তাদের কাজের প্রক্রিয়া নিয়ে আলোচনা করব।
Spring Batch হল একটি ফ্রেমওয়ার্ক যা ব্যাচ প্রসেসিংয়ের জন্য তৈরি করা হয়েছে। এটি ব্যবহৃত হয় দীর্ঘ-running ব্যাচ অ্যাপ্লিকেশনগুলির জন্য যেমন বড় ডেটা সেট প্রক্রিয়া, ডেটা কনভার্শন, রিপোর্টিং ইত্যাদি। Spring Batch মূলত Job, Step, Tasklet, এবং ItemReader, ItemProcessor, ItemWriter এর সমন্বয়ে কাজ করে।
Job হল স্প্রিং ব্যাচের মূল একক যা ব্যাচ প্রসেসিংয়ের পুরো প্রক্রিয়া পরিচালনা করে। একটি Job একটি বা একাধিক Step নিয়ে গঠিত। এটি একটি কনটেইনার হিসেবে কাজ করে যা একাধিক স্টেপ (যেমন ডেটা রিড, প্রসেস এবং রাইট) পরিচালনা করতে সক্ষম।
@Bean
public Job exampleJob(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory) {
return jobBuilderFactory.get("exampleJob")
.start(step1())
.next(step2())
.build();
}
এখানে, exampleJob একটি Job যা দুটি Step (step1 এবং step2) এর মাধ্যমে প্রসেসিং করবে। একটি Job বিভিন্ন Step এর মাধ্যমে একাধিক কাজ সম্পাদন করতে পারে।
Step একটি ব্যাচ প্রসেসিংয়ের ছোট একক কাজ, যা ডেটা রিডিং, প্রসেসিং বা লেখার মতো কাজ করতে পারে। একটি Job একাধিক Step নিয়ে গঠিত। প্রতিটি Step একটি নির্দিষ্ট কার্যক্রম যেমন ItemReader, ItemProcessor, এবং ItemWriter ব্যবহার করে একটি কাজ সম্পাদন করে। একটি Step সাধারণত ব্যাচ কাজের একক লজিক বা কাজের একটি নির্দিষ্ট অংশকে প্রতিনিধিত্ব করে।
@Bean
public Step step1(StepBuilderFactory stepBuilderFactory) {
return stepBuilderFactory.get("step1")
.<String, String>chunk(10)
.reader(new MyItemReader())
.processor(new MyItemProcessor())
.writer(new MyItemWriter())
.build();
}
এখানে, step1 একটি Step যা MyItemReader, MyItemProcessor, এবং MyItemWriter ব্যবহার করে ডেটা রিড, প্রসেস এবং রাইট করবে। chunk(10) এর মাধ্যমে এটি প্রতি চাঙ্কে ১০টি রেকর্ড প্রসেস করবে।
Tasklet হল স্প্রিং ব্যাচের একটি একক কাজ যা একটি নির্দিষ্ট কাজ বা কার্যক্রম সম্পাদন করে। এটি Step এর মধ্যে ব্যবহার করা যেতে পারে, যেখানে আপনি কোনো একটি নির্দিষ্ট কাজ (যেমন একটি স্ক্রিপ্ট চালানো, ফাইল কপি করা) করতে চান, যা ItemReader, ItemProcessor, এবং ItemWriter ব্যবহারের বাইরে। Tasklet সাধারণত ব্যাচ প্রসেসিংয়ের মধ্যে কোন নির্দিষ্ট কাজ সম্পাদন করতে ব্যবহৃত হয়।
@Bean
public Step taskletStep(StepBuilderFactory stepBuilderFactory) {
return stepBuilderFactory.get("taskletStep")
.tasklet(new MyTasklet())
.build();
}
এখানে, taskletStep একটি Step যা MyTasklet নামক একটি কাস্টম Tasklet ক্লাস ব্যবহার করে নির্দিষ্ট কাজ সম্পাদন করবে।
public class MyTasklet implements Tasklet {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
// Custom task logic here
System.out.println("Tasklet executed!");
return RepeatStatus.FINISHED; // Indicating task is finished
}
}
এখানে, MyTasklet ক্লাসটি Tasklet ইন্টারফেসকে ইমপ্লিমেন্ট করে এবং execute() মেথডে কাস্টম কাজ সম্পাদন করে।
RepeatStatus হল একটি enum যা Tasklet এর কাজের অবস্থা নির্দেশ করে:
Spring Batch এর কাজের প্রক্রিয়া মূলত নিম্নলিখিত পর্যায়ে চলে:
Spring Batch একটি শক্তিশালী ফ্রেমওয়ার্ক যা বড় ডেটাসেট এবং দীর্ঘ-running প্রসেসিংয়ের জন্য ব্যবহৃত হয়। এটি Job, Step, এবং Tasklet এর মাধ্যমে কাজ করে:
স্প্রিং ব্যাচের মাধ্যমে আপনি বড় পরিমাণ ডেটা প্রক্রিয়া করার জন্য খুবই কার্যকর এবং স্কেলেবল অ্যাপ্লিকেশন তৈরি করতে পারেন।
Spring Batch হল একটি শক্তিশালী ফ্রেমওয়ার্ক যা বিশেষভাবে ব্যাচ প্রসেসিং (যেমন ডেটা মাইগ্রেশন, রিপোর্ট জেনারেশন, ইত্যাদি) সম্পাদন করার জন্য ডিজাইন করা হয়েছে। এটি বড় পরিমাণ ডেটার সাথে কাজ করার জন্য বিশেষভাবে প্রস্তুত, এবং বিভিন্ন ধরনের ডেটা প্রসেসিং স্টেপ (যেমন রিড, প্রসেস এবং রাইট) সম্পাদন করার জন্য সুবিধা প্রদান করে।
স্প্রিং ব্যাচের মাধ্যমে আপনি ইনপুট ডেটা (যেমন ফাইল, ডেটাবেস) থেকে আউটপুট ডেটা (যেমন ফাইল, ডেটাবেস, কনসোল) তৈরি করতে পারেন। এখানে আমরা Spring Batch Processing তৈরি করার একটি উদাহরণ দেখব, যেখানে আমরা একটি ব্যাচ জব তৈরি করব যা ডেটাবেস থেকে ডেটা পড়ে, প্রক্রিয়া করে এবং ফলাফল একটি ফাইলে রাইট করবে।
স্প্রিং ব্যাচ প্রধানত নিম্নলিখিত উপাদানগুলি নিয়ে গঠিত:
স্প্রিং ব্যাচ প্রসেসিং সিস্টেমের জন্য কনফিগারেশন ক্লাস তৈরি করতে হবে যাতে Job, Step, ItemReader, ItemProcessor, এবং ItemWriter কনফিগার করা যায়।
এখানে একটি উদাহরণ দেওয়া হলো যেখানে আমরা Spring Batch ব্যবহার করে একটি CSV ফাইল থেকে ডেটা রিড করব, ডেটা প্রসেস করব এবং একটি ফাইল বা ডেটাবেসে রাইট করব।
প্রথমে, স্প্রিং বুট অ্যাপ্লিকেশন তৈরি করতে হবে, এবং স্প্রিং ব্যাচের জন্য প্রয়োজনীয় কনফিগারেশন যোগ করতে হবে। pom.xml ফাইলের জন্য প্রয়োজনীয় ডিপেনডেন্সি যোগ করুন:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-infrastructure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.core.JobParametersValidator;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableBatchProcessing
public class BatchConfig {
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
public BatchConfig(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory) {
this.jobBuilderFactory = jobBuilderFactory;
this.stepBuilderFactory = stepBuilderFactory;
}
// Define an ItemReader
@Bean
public ItemReader<String> reader() {
return new FileReader(); // You can implement the logic of reading data from CSV or other sources
}
// Define an ItemProcessor
@Bean
public ItemProcessor<String, String> processor() {
return new UppercaseProcessor(); // Simple processor that converts the data to uppercase
}
// Define an ItemWriter
@Bean
public ItemWriter<String> writer() {
return new FileWriter(); // You can implement the logic of writing to a file
}
// Step Definition
@Bean
public Step step1() {
return stepBuilderFactory.get("step1")
.<String, String> chunk(10) // Define chunk size
.reader(reader())
.processor(processor())
.writer(writer())
.build();
}
// Job Definition
@Bean
public Job processJob() {
return jobBuilderFactory.get("processJob")
.incrementer(new RunIdIncrementer()) // Job will have a unique ID for each execution
.start(step1()) // Starting point of the job
.build();
}
}
import org.springframework.batch.item.ItemReader;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class FileReader implements ItemReader<String> {
private BufferedReader reader;
@Override
public String read() throws Exception {
if (reader == null) {
reader = new BufferedReader(new java.io.FileReader("data.csv"));
}
return reader.readLine(); // Read each line from the file
}
}
import org.springframework.batch.item.ItemProcessor;
public class UppercaseProcessor implements ItemProcessor<String, String> {
@Override
public String process(String item) throws Exception {
return item.toUpperCase(); // Convert the string to uppercase
}
}
import org.springframework.batch.item.ItemWriter;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
public class FileWriter implements ItemWriter<String> {
private BufferedWriter writer;
@Override
public void write(List<? extends String> items) throws Exception {
if (writer == null) {
writer = new BufferedWriter(new java.io.FileWriter("output.txt"));
}
for (String item : items) {
writer.write(item);
writer.newLine();
}
writer.flush();
}
}
স্প্রিং বুট অ্যাপ্লিকেশন চালাতে, আপনাকে একটি Main Application ক্লাস তৈরি করতে হবে যা @SpringBootApplication
অ্যানোটেশন সহ হবে।
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BatchApplication {
public static void main(String[] args) {
SpringApplication.run(BatchApplication.class, args);
}
}
স্প্রিং ব্যাচের মধ্যে JobLauncher ব্যবহার করে ব্যাচ জব চালানো যায়। এটি ব্যাচ জবের স্টার্ট এবং এক্সিকিউশন পরিচালনা করে।
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.launch.JobExecution;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class BatchJobRunner implements CommandLineRunner {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private Job processJob;
@Override
public void run(String... args) throws Exception {
JobExecution jobExecution = jobLauncher.run(processJob, new org.springframework.batch.core.JobParameters());
System.out.println("Job Status: " + jobExecution.getStatus());
}
}
এখন আপনার স্প্রিং ব্যাচ অ্যাপ্লিকেশনটি চালানোর জন্য প্রস্তুত। এটি ডেটা রিড করবে, প্রসেস করবে এবং আউটপুট ফাইলে লেখাবে। আপনি java -jar your-application.jar
কমান্ড দিয়ে অ্যাপ্লিকেশনটি চালু করতে পারেন এবং ফলস্বরূপ ডেটা আউটপুট ফাইলে পাওয়া যাবে।
Spring Batch একটি শক্তিশালী ফ্রেমওয়ার্ক যা ডেটা ব্যাচ প্রসেসিংয়ের জন্য ব্যবহৃত হয়। এর মাধ্যমে আপনি সহজেই ডেটাবেস থেকে ডেটা রিড, প্রসেস এবং আউটপুটে লেখার মতো কার্যক্রম করতে পারেন। এখানে, স্প্রিং ব্যাচের ItemReader, ItemProcessor, এবং ItemWriter ব্যবহার করে একটি সিম্পল ব্যাচ প্রসেসিং অ্যাপ্লিকেশন তৈরি করা হয়েছে, যা CSV ফাইল থেকে ডেটা রিড করে এবং output.txt ফাইলে প্রক্রিয়া করা ডেটা লেখে।
Read more