Partner – Orkes – NPI EA (cat=Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag=Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Partner – Orkes – NPI EA (cat=Java)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

1. Overview

When maintaining or transforming text data, we often need to modify the content of existing files. In Java, there are multiple ways to accomplish this, depending on the file size and our performance needs. Small files can be easily handled in memory, while large files are better processed line by line using streams.

In this tutorial, we’ll explore two approaches to modify a file’s content based on patterns. Both approaches rely on Java’s modern Java NIO APIs.

2. Introduction to the Problem

Before jumping into code, let’s define the problem we want to solve.

2.1. Defining the Problem

Imagine that we are given a text file containing lines about various programming languages. Here’s what it looks like:

Both JAVA and KOTLIN applications can run on the JVM.
But python is a simpler language
PYTHON application is also platform independent.
java and kotlin are statically typed languages.
On the other hand, python is a dynamically typed language.

We want to clean up and normalize this content by performing several text transformations:

  • Remove the second line.
  • Normalize capitalization – Convert all occurrences of “java”, “kotlin”, and “python” to their correctly capitalized forms “Java“, “Kotlin“, and “Python
  • Expand abbreviations – Wherever “JVM” appears, add its complete form “(Java Virtual Machine)” after it.
  • Write back the changes to the original file.

At the end, our modified file should look like this:

Both Java and Kotlin applications can run on the JVM (Java Virtual Machine).
Python application is also platform independent.
Java and Kotlin are statically typed languages.
On the other hand, Python is a dynamically typed language.

As usual, we’ll use unit test methods to demonstrate each approach. So next, let’s set up our unit test class.

2.2. Setting up the Test

Let’s first look at the unit test setup:

public class ModifyFileByPatternUnitTest {
    @TempDir
    private File fileDir;

    private File myFile;

    private static final List<String> ORIGINAL_LINES = List.of(
      "Both JAVA and KOTLIN applications can run on the JVM.",
      "But python is a simpler language",
      "PYTHON application is also platform independent.",
      "java and kotlin are statically typed languages.",
      "On the other hand, python is a dynamically typed language.");

    private static final List<String> EXPECTED_LINES = List.of(
      "Both Java and Kotlin applications can run on the JVM (Java Virtual Machine).",
      "Python application is also platform independent.",
      "Java and Kotlin are statically typed languages.",
      "On the other hand, Python is a dynamically typed language.");

    @BeforeEach
    void initFile() throws IOException {
        myFile = new File(fileDir, "myFile.txt");
        Files.write(myFile.toPath(), ORIGINAL_LINES);
    }

    // ...
}

As we can see, to ensure that our tests don’t modify any real files on the system, we’ll take advantage of the @TempDir annotation, which allows us to create a temporary directory that exists only for the duration of the test. Once the test finishes, JUnit automatically deletes all files inside it. This provides a clean, isolated environment for every run.

Additionally, the initFile() method ensures that every test begins with the same initial file content, thereby ensuring our modifications are tested in a controlled environment.

Next, let’s see how to solve this problem.

3. Loading the Entire File into Memory

Our first approach is to load the entire file into memory, modify its contents, and write it back. This technique is simple and effective for small or moderately sized files.

Let’s check how this is done:

@Test
void whenLoadTheFileContentToMemModifyThenWriteBack_thenCorrect() throws IOException {
    assertTrue(Files.exists(myFile.toPath()));
    List<String> lines = Files.readAllLines(myFile.toPath());
    lines.remove(1); // remove the 2nd line
    List<String> newLines = lines.stream()
      .map(line -> line.replaceAll("(?i)java", "Java")
        .replaceAll("(?i)kotlin", "Kotlin")
        .replaceAll("(?i)python", "Python")
        .replaceAll("JVM", "$0 (Java Virtual Machine)"))
      .toList();
    Files.write(myFile.toPath(), newLines);
    assertLinesMatch(EXPECTED_LINES, Files.readAllLines(myFile.toPath()));
}

In this approach, we first read all lines from the file into a List using Files.readAllLines(). Then, we removed the second line and performed the pattern replacements. Finally, we used Files.write() overwrites the file directly with the updated lines.

It’s worth mentioning that we used JUnit 5’s assertLinesMatch() to verify the file content.

This in-memory approach is concise and easy to reason about. However, it’s not ideal for huge files where memory usage becomes a concern.

So next, let’s assume myFile.txt is a huge file and explore how to solve the problem.

4. Memory-Efficient File Modification Using BufferedReader

To handle larger files efficiently, we can use streaming IO with BufferedReader and BufferedWriter. This method processes one line at a time without loading the entire file into memory.

Next, let’s have a look at the implementation:

@Test
void whenUsingBufferedReaderAndModifyViaTempFile_thenCorrect(@TempDir Path tempDir) throws IOException {
    Pattern javaPat = Pattern.compile("(?i)java");
    Pattern kotlinPat = Pattern.compile("(?i)kotlin");
    Pattern pythonPat = Pattern.compile("(?i)python");
    Pattern jvmPat = Pattern.compile("JVM");

    Path modifiedFile = tempDir.resolve("modified.txt");

    try (BufferedReader reader = Files.newBufferedReader(myFile.toPath());
      BufferedWriter writer = Files.newBufferedWriter(modifiedFile)) {

        int lineNumber = 0;
        String line;
        while ((line = reader.readLine()) != null) {
            lineNumber++;
            if (lineNumber == 2) {
                continue; // skip the 2nd line
            }

            String replaced = line;
            replaced = javaPat.matcher(replaced)
              .replaceAll("Java");
            replaced = kotlinPat.matcher(replaced)
              .replaceAll("Kotlin");
            replaced = pythonPat.matcher(replaced)
              .replaceAll("Python");
            replaced = jvmPat.matcher(replaced)
              .replaceAll("JVM (Java Virtual Machine)");

            writer.write(replaced);
            writer.newLine();
        }
    }

    Files.move(modifiedFile, myFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
    assertTrue(myFile.exists());
    assertLinesMatch(EXPECTED_LINES, Files.readAllLines(myFile.toPath()));
}

Next, let’s understand the details.

  • Precompiled Regex Patterns – Instead of calling replaceAll() directly on Strings, we compile the Regex patterns once using Pattern.compile(). This is more efficient when applying the same patterns multiple times.
  • Streaming with BufferedReader and BufferedWriterWe read the file line by line, modify each one, and write it immediately to a temporary output file (modified.txt). This keeps memory usage low regardless of file size.
  • Try-with-resources – The try (…) { … } syntax automatically closes both reader and writer when the block finishes. It’s a safer and cleaner alternative to manually closing streams in a finally block.
  • Replacing the original file – Once writing is complete, we replace the original file with the modified one using Files.move() and the REPLACE_EXISTING option.

This method is robust, scalable, and well-suited for large files or streaming scenarios that require fine-grained control over processing.

5. Conclusion

In this article, we explored two practical techniques for modifying a file’s content in Java based on regular expression patterns:

  • Loading the entire file into memory — It’s a simple and expressive solution, ideal for smaller files.
  • Streaming with BufferedReader and BufferedWriter — It’s an efficient and scalable approach for handling large files.

Both methods build upon Java’s standard libraries, so they work in any Java environment without extra dependencies. By combining these approaches, we can handle a wide range of file transformation tasks safely and efficiently.

As always, the complete source code for the examples is available over on GitHub.

Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

Partner – Orkes – NPI EA (cat = Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag = Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

eBook Jackson – NPI EA – 3 (cat = Jackson)
guest
0 Comments
Oldest
Newest
Inline Feedbacks
View all comments