I have a linux server and many clients with many operating systems. The server takes an input file from clients. Linux has end of line char LF, while Mac has end of line char CR, and
Windows has end of line char CR+LF
The server needs as end of line char LF. Using java, I want to ensure that the file will always use the linux eol char LF. How can I achieve it?
Could you try this?
content.replaceAll("\\r\\n?", "\n")
Combining the two answers (by Visage & eumiro):
EDIT: After reading the comment. line.
System.getProperty("line.separator") has no use then.
Before sending the file to server, open it replace all the EOLs and writeback
Make sure to use DataStreams to do so, and write in binary
String fileString;
//..
//read from the file
//..
//for windows
fileString = fileString.replaceAll("\\r\\n", "\n");
fileString = fileString.replaceAll("\\r", "\n");
//..
//write to file in binary mode.. something like:
DataOutputStream os = new DataOutputStream(new FileOutputStream("fname.txt"));
os.write(fileString.getBytes());
//..
//send file
//..
The replaceAll method has two arguments, the first one is the string to replace and the second one is the replacement. But, the first one is treated as a regular expression, so, '\' is interpreted that way. So:
"\\r\\n" is converted to "\r\n" by Regex
"\r\n" is converted to CR+LF by Java
Had to do this for a recent project. The method below will normalize the line endings in the given file to the line ending specified by the OS the JVM is running on. So if you JVM is running on Linux, this will normalize all line endings to LF (\n).
Also works on very large files due to the use of buffered streams.
public static void normalizeFile(File f) {
File temp = null;
BufferedReader bufferIn = null;
BufferedWriter bufferOut = null;
try {
if(f.exists()) {
// Create a new temp file to write to
temp = new File(f.getAbsolutePath() + ".normalized");
temp.createNewFile();
// Get a stream to read from the file un-normalized file
FileInputStream fileIn = new FileInputStream(f);
DataInputStream dataIn = new DataInputStream(fileIn);
bufferIn = new BufferedReader(new InputStreamReader(dataIn));
// Get a stream to write to the normalized file
FileOutputStream fileOut = new FileOutputStream(temp);
DataOutputStream dataOut = new DataOutputStream(fileOut);
bufferOut = new BufferedWriter(new OutputStreamWriter(dataOut));
// For each line in the un-normalized file
String line;
while ((line = bufferIn.readLine()) != null) {
// Write the original line plus the operating-system dependent newline
bufferOut.write(line);
bufferOut.newLine();
}
bufferIn.close();
bufferOut.close();
// Remove the original file
f.delete();
// And rename the original file to the new one
temp.renameTo(f);
} else {
// If the file doesn't exist...
log.warn("Could not find file to open: " + f.getAbsolutePath());
}
} catch (Exception e) {
log.warn(e.getMessage(), e);
} finally {
// Clean up, temp should never exist
FileUtils.deleteQuietly(temp);
IOUtils.closeQuietly(bufferIn);
IOUtils.closeQuietly(bufferOut);
}
}
Here is a comprehensive helper class to deal with EOL issues. It it partially based on the solution posted by tyjen.
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
/**
* Helper class to deal with end-of-line markers in text files.
*
* Loosely based on these examples:
* - http://stackoverflow.com/a/9456947/1084488 (cc by-sa 3.0)
* - https://github.com/apache/tomcat/blob/main/java/org/apache/tomcat/buildutil/CheckEol.java (Apache License v2.0)
*
* This file is posted here to meet the "ShareAlike" requirement of cc by-sa 3.0:
* http://stackoverflow.com/a/27930311/1084488
*
* #author Matthias Stevens
*/
public class EOLUtils
{
/**
* Unix-style end-of-line marker (LF)
*/
private static final String EOL_UNIX = "\n";
/**
* Windows-style end-of-line marker (CRLF)
*/
private static final String EOL_WINDOWS = "\r\n";
/**
* "Old Mac"-style end-of-line marker (CR)
*/
private static final String EOL_OLD_MAC = "\r";
/**
* Default end-of-line marker on current system
*/
private static final String EOL_SYSTEM_DEFAULT = System.getProperty( "line.separator" );
/**
* The support end-of-line marker modes
*/
public static enum Mode
{
/**
* Unix-style end-of-line marker ("\n")
*/
LF,
/**
* Windows-style end-of-line marker ("\r\n")
*/
CRLF,
/**
* "Old Mac"-style end-of-line marker ("\r")
*/
CR
}
/**
* The default end-of-line marker mode for the current system
*/
public static final Mode SYSTEM_DEFAULT = ( EOL_SYSTEM_DEFAULT.equals( EOL_UNIX ) ? Mode.LF : ( EOL_SYSTEM_DEFAULT
.equals( EOL_WINDOWS ) ? Mode.CRLF : ( EOL_SYSTEM_DEFAULT.equals( EOL_OLD_MAC ) ? Mode.CR : null ) ) );
static
{
// Just in case...
if ( SYSTEM_DEFAULT == null )
{
throw new IllegalStateException( "Could not determine system default end-of-line marker" );
}
}
/**
* Determines the end-of-line {#link Mode} of a text file.
*
* #param textFile the file to investigate
* #return the end-of-line {#link Mode} of the given file, or {#code null} if it could not be determined
* #throws Exception
*/
public static Mode determineEOL( File textFile )
throws Exception
{
if ( !textFile.exists() )
{
throw new IOException( "Could not find file to open: " + textFile.getAbsolutePath() );
}
FileInputStream fileIn = new FileInputStream( textFile );
BufferedInputStream bufferIn = new BufferedInputStream( fileIn );
try
{
int prev = -1;
int ch;
while ( ( ch = bufferIn.read() ) != -1 )
{
if ( ch == '\n' )
{
if ( prev == '\r' )
{
return Mode.CRLF;
}
else
{
return Mode.LF;
}
}
else if ( prev == '\r' )
{
return Mode.CR;
}
prev = ch;
}
throw new Exception( "Could not determine end-of-line marker mode" );
}
catch ( IOException ioe )
{
throw new Exception( "Could not determine end-of-line marker mode", ioe );
}
finally
{
// Clean up:
IOUtils.closeQuietly( bufferIn );
}
}
/**
* Checks whether the given text file has Windows-style (CRLF) line endings.
*
* #param textFile the file to investigate
* #return
* #throws Exception
*/
public static boolean hasWindowsEOL( File textFile )
throws Exception
{
return Mode.CRLF.equals( determineEOL( textFile ) );
}
/**
* Checks whether the given text file has Unix-style (LF) line endings.
*
* #param textFile the file to investigate
* #return
* #throws Exception
*/
public static boolean hasUnixEOL( File textFile )
throws Exception
{
return Mode.LF.equals( determineEOL( textFile ) );
}
/**
* Checks whether the given text file has "Old Mac"-style (CR) line endings.
*
* #param textFile the file to investigate
* #return
* #throws Exception
*/
public static boolean hasOldMacEOL( File textFile )
throws Exception
{
return Mode.CR.equals( determineEOL( textFile ) );
}
/**
* Checks whether the given text file has line endings that conform to the system default mode (e.g. LF on Unix).
*
* #param textFile the file to investigate
* #return
* #throws Exception
*/
public static boolean hasSystemDefaultEOL( File textFile )
throws Exception
{
return SYSTEM_DEFAULT.equals( determineEOL( textFile ) );
}
/**
* Convert the line endings in the given file to Unix-style (LF).
*
* #param textFile the file to process
* #throws IOException
*/
public static void convertToUnixEOL( File textFile )
throws IOException
{
convertLineEndings( textFile, EOL_UNIX );
}
/**
* Convert the line endings in the given file to Windows-style (CRLF).
*
* #param textFile the file to process
* #throws IOException
*/
public static void convertToWindowsEOL( File textFile )
throws IOException
{
convertLineEndings( textFile, EOL_WINDOWS );
}
/**
* Convert the line endings in the given file to "Old Mac"-style (CR).
*
* #param textFile the file to process
* #throws IOException
*/
public static void convertToOldMacEOL( File textFile )
throws IOException
{
convertLineEndings( textFile, EOL_OLD_MAC );
}
/**
* Convert the line endings in the given file to the system default mode.
*
* #param textFile the file to process
* #throws IOException
*/
public static void convertToSystemEOL( File textFile )
throws IOException
{
convertLineEndings( textFile, EOL_SYSTEM_DEFAULT );
}
/**
* Line endings conversion method.
*
* #param textFile the file to process
* #param eol the end-of-line marker to use (as a {#link String})
* #throws IOException
*/
private static void convertLineEndings( File textFile, String eol )
throws IOException
{
File temp = null;
BufferedReader bufferIn = null;
BufferedWriter bufferOut = null;
try
{
if ( textFile.exists() )
{
// Create a new temp file to write to
temp = new File( textFile.getAbsolutePath() + ".normalized" );
temp.createNewFile();
// Get a stream to read from the file un-normalized file
FileInputStream fileIn = new FileInputStream( textFile );
DataInputStream dataIn = new DataInputStream( fileIn );
bufferIn = new BufferedReader( new InputStreamReader( dataIn ) );
// Get a stream to write to the normalized file
FileOutputStream fileOut = new FileOutputStream( temp );
DataOutputStream dataOut = new DataOutputStream( fileOut );
bufferOut = new BufferedWriter( new OutputStreamWriter( dataOut ) );
// For each line in the un-normalized file
String line;
while ( ( line = bufferIn.readLine() ) != null )
{
// Write the original line plus the operating-system dependent newline
bufferOut.write( line );
bufferOut.write( eol ); // write EOL marker
}
// Close buffered reader & writer:
bufferIn.close();
bufferOut.close();
// Remove the original file
textFile.delete();
// And rename the original file to the new one
temp.renameTo( textFile );
}
else
{
// If the file doesn't exist...
throw new IOException( "Could not find file to open: " + textFile.getAbsolutePath() );
}
}
finally
{
// Clean up, temp should never exist
FileUtils.deleteQuietly( temp );
IOUtils.closeQuietly( bufferIn );
IOUtils.closeQuietly( bufferOut );
}
}
}
Use
System.getProperty("line.separator")
That will give you the (local) EOL character(s). You can then use an analysis of the incomifile to determine what 'flavour' it is and convert accordingly.
Alternatively, get your clients to standardise!
public static String normalize(String val) {
return val.replace("\r\n", "\n")
.replace("\r", "\n");
}
For HTML:
public static String normalize(String val) {
return val.replace("\r\n", "<br/>")
.replace("\n", "<br/>")
.replace("\r", "<br/>");
}
solution to change the file ending with recursive search in path
package handleFileLineEnd;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import sun.awt.image.BytePackedRaster;
public class handleFileEndingMain {
static int carriageReturnTotal;
static int newLineTotal;
public static void main(String[] args) throws IOException
{
processPath("c:/temp/directories");
System.out.println("carriageReturnTotal (files have issue): " + carriageReturnTotal);
System.out.println("newLineTotal: " + newLineTotal);
}
private static void processPath(String path) throws IOException
{
File dir = new File(path);
File[] directoryListing = dir.listFiles();
if (directoryListing != null) {
for (File child : directoryListing) {
if (child.isDirectory())
processPath(child.toString());
else
checkFile(child.toString());
}
}
}
private static void checkFile(String fileName) throws IOException
{
Path path = FileSystems.getDefault().getPath(fileName);
byte[] bytes= Files.readAllBytes(path);
for (int counter=0; counter<bytes.length; counter++)
{
if (bytes[counter] == 13)
{
carriageReturnTotal = carriageReturnTotal + 1;
System.out.println(fileName);
modifyFile(fileName);
break;
}
if (bytes[counter] == 10)
{
newLineTotal = newLineTotal+ 1;
//System.out.println(fileName);
break;
}
}
}
private static void modifyFile(String fileName) throws IOException
{
Path path = Paths.get(fileName);
Charset charset = StandardCharsets.UTF_8;
String content = new String(Files.readAllBytes(path), charset);
content = content.replaceAll("\r\n", "\n");
content = content.replaceAll("\r", "\n");
Files.write(path, content.getBytes(charset));
}
}
Although String.replaceAll() is simpler to code, this should perform better since it doesn't go through the regex infrastructure.
/**
* Accepts a non-null string and returns the string with all end-of-lines
* normalized to a \n. This means \r\n and \r will both be normalized to \n.
* <p>
* Impl Notes: Although regex would have been easier to code, this approach
* will be more efficient since it's purpose built for this use case. Note we only
* construct a new StringBuilder and start appending to it if there are new end-of-lines
* to be normalized found in the string. If there are no end-of-lines to be replaced
* found in the string, this will simply return the input value.
* </p>
*
* #param inputValue !null, input value that may or may not contain new lines
* #return the input value that has new lines normalized
*/
static String normalizeNewLines(String inputValue){
StringBuilder stringBuilder = null;
int index = 0;
int len = inputValue.length();
while (index < len){
char c = inputValue.charAt(index);
if (c == '\r'){
if (stringBuilder == null){
stringBuilder = new StringBuilder();
// build up the string builder so it contains all the prior characters
stringBuilder.append(inputValue.substring(0, index));
}
if ((index + 1 < len) &&
inputValue.charAt(index + 1) == '\n'){
// this means we encountered a \r\n ... move index forward one more character
index++;
}
stringBuilder.append('\n');
}else{
if (stringBuilder != null){
stringBuilder.append(c);
}
}
index++;
}
return stringBuilder == null ? inputValue : stringBuilder.toString();
}
Since Java 12 you can use
var str = str.indent(0);
which implicitly normalizes the EOF characters.
Or more explicitly
var str = str.lines().collect(Collectors.joining("\n", "", "\n"))
Related
Trying to reverse a file line by line
public static void main(String[] args) throws FileNotFoundException {
System.out.println("filname: ");
Scanner input = new Scanner(System.in);
String filnamn = input.nextLine();
File file = new File(filnamn);
Scanner inputFile = new Scanner(file);
PrintWriter writer = new PrintWriter(file);
while (input.hasNextLine()) {
String fil = input.next();
int reverse = 0;
for (int i = fil.length(); i >= 0; i--) {
reverse = reverse + fil.charAt(i);
writer.print(reverse);
}
}
inputFile.close();
writer.close();
input.close();
}
When trying to reverse my file it just get erased instead of it being backwards
You are not reading the file at all, but instead input (console).
That means your program is waiting for you to enter text.
Also your file gets deleted since you are trying to write to it.
Switch your while loop to read from inputFile instead of input.
Remove the line, or come up with a different output file:
PrintWriter writer = new PrintWriter(file);
You have an issue with the path of file.
You can extract the full path by -
System.out.println("filname: ");
Scanner input = new Scanner(System.in);
String filnamn = input.nextLine();
// Add this
final String fullPath = <YOUR_CLASS>.class.getProtectionDomain().getCodeSource().getLocation().getPath();
// Then correct the path
File file = new File(fullPath_filnamn);
Scanner inputFile = new Scanner(file);
PrintWriter writer = new PrintWriter(file);
while (input.hasNextLine()) {
String fil = input.next();
int reverse = 0;
for (int i = fil.length(); i >= 0; i--) {
reverse = reverse + fil.charAt(i);
writer.print(reverse);
}
}
inputFile.close();
writer.close();
input.close();
It's not quite clear if it is each entire line that is in the file that is to be revered or each word within each line is to be reversed, there is a major difference between the two. In any case the method provided below can do either.
You can not write to the file you are reading from, you will need to provide a different file name. What you can do however is when the new file is created and your code has closed both the reader and writer, you can delete the original file and then rename the new file with the name of the original file. As you will see, this is only a few small lines of code.
You're reading the User's input instead of the input file. This is why it's important to give clear, distinguishable, and meaningful names to your variables like reader instead of inputFile which is close to the Scanner Keyboard input name of input). It can be easy to make mistakes if the variable names are similar or non-descriptive.
Here is the method:
/**
* Rewrites the supplied file into a new file where every word in that file
* has its characters reversed. The new file created (in the same directory)
* is named exactly the same except it will contain the file name extension
* of ".temp" unless, the `overwriteFile` option was passed boolean true in
* which case the original file is overwritten.<br><br>
*
* This method will need to be wrapped within a try/catch block.<br>
*
* #param fileName (String) the full path and file name (including file name
* extension) to the file which is to be reversed.<br>
*
* #param options (optional - Boolean - Two of):<pre>
*
* reverseEntireLine - Default is false where each word in each file line
* will be separately reversed. If boolean true is
* optionally supplied then each entire line is
* reversed. If null is supplied then false is implied.
*
* Whitespacing (indents, etc) in the file is also
* taken into consideration and maintained.
*
* overwriteFile - Default is false where the original file being
* read is not overwriten with reversed text but
* instead a new file is created under the same name,
* within the same directory, containing a file name
* extension of ".temp". If boolean true is supplied
* to this optional parameter then the original file
* will be overwriten. It should be noted that there
* is no actual overwrite. The original file is actually
* deleted and then the new file is renamed to the
* original file name. This will allow for extremely
* large files to be overwriten without the worry of
* memory exhaustion.<pre>
*
* #throws FileNotFoundException
* #throws IOException
*/
public static void reverseFile(String fileName, Boolean... options)
throws FileNotFoundException, IOException {
// false = each word in line | true = entire line.
boolean reverseEntireLine = false;
// false = Not Overwrite File | true = Overwrite File.
boolean overwriteFile = false;
if (options.length > 0) {
if (options.length >= 1 && options[0] != null) {
reverseEntireLine = options[0];
}
if (options.length >= 2 && options[1] != null) {
overwriteFile = options[1];
}
}
File fileToRead = new File(fileName); // Create a File object.
/* Create a name for a temporary file to write in
within the same path of the file we are about
to read. This name will be the same but will
have the file name extension of ".temp". */
String fullPath = fileToRead.getAbsolutePath();
String tempFile = fullPath.substring(0, fullPath.lastIndexOf(".")) + ".temp";
/* You can not write to the file you are reading from.
Provide a different (temporary) name. */
/* 'Try With Resources' is used here for both the reader and writer so
to auto-close() them when done and free resources. */
try (BufferedReader reader = new BufferedReader(new java.io.InputStreamReader(
new java.io.FileInputStream(fullPath), "UTF-8"))) {
java.io.OutputStream os = new java.io.FileOutputStream(tempFile);
try (PrintWriter writer = new PrintWriter(new java.io.OutputStreamWriter(os, "UTF-8"))) {
// Iterate if the file has another line...
String line;
while ((line = reader.readLine()) != null) {
// If the line is blank then just print it and continue to next line
if (line.trim().isEmpty()) {
writer.println();
continue; // read next line....
}
StringBuilder sb = new StringBuilder("");
if (reverseEntireLine) {
// Reverse the entire line
sb.append(line).reverse();
}
else {
/* Reverse each word within the currently read line:
Split the line into individual words based on whitespace but,
keep any spacing in case there is indentation etc. We use a
special Regular Expression for this because spacing needs to
be in thier own elements within the created String[] Array
even though we're using it as a split() delimiter. */
String splitExpression = "((?<= )|(?= ))";
String[] lineParts = line.split(splitExpression);
for (String word : lineParts) {
if (word.matches("\\s+")) {
sb.append(word);
}
else {
word = new StringBuilder(word).reverse().toString();
sb.append(word);
}
}
}
writer.println(sb.toString()); // Write to file.
writer.flush(); // Write immediately.
}
}
}
if (overwriteFile) {
new File(fullPath).delete();
new File(tempFile).renameTo(new File(fullPath));
}
}
And here is how you might use it:
/* The Line Spearator used for the system the application
is running on. Not all Consoles or Terminals just use "\n". */
String ls = System.lineSeparator();
// Provide a distinguishable and meaningful variable name!
Scanner userInput = new Scanner(System.in);
// File name to read prompt...
String fileName = "";
while (fileName.isEmpty()) {
System.out.print("Please enter the file path and name of the file" + ls
+ "you want to reverse (q to quit): -> ");
fileName = userInput.nextLine().trim();
// If 'q' for quit was entered.
if (fileName.equalsIgnoreCase("q")) {
return;
}
/* Validate input!
Does the supplied path and fileName exist? */
if (!new File(fileName).exists()) {
// Nope! Inform User...
System.out.println("The file name (" + fileName + ") can not be found!" + ls
+ "Please, try again..." + ls);
fileName = ""; // Empty fileName so to re-loop and ask again!
}
}
// All is good, the path and or file name exists.
try {
reverseFile(fileName, true, true); // <----
}
catch (FileNotFoundException ex) {
System.err.println(ex);
}
catch (IOException ex) {
System.err.println(ex);
}
I'm working with a Java program on Eclipse. The program gets the "txt" file name from the user and print out the number of lines in that "txt" file ("There are "x" lines in the file"). If the "txt" file does not exist, it should print out "That file does not exist"
I am trying to get the program to keep looping, asking for a file name regardless of whether the last entry resulted in an error or not, until the user types "Done".
This is the code I am editing. There are 2 classes total. This is the first (ProcessFile.java):
// ProcessFile.java
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
/**
*
* This class will ask the user for a text file
* name, open that file, and print all the lines
* of the file and how many lines there are.
*
*
*/
public class ProcessFile {
/**
* This method prompts the user to enter a
* file name and returns it.
*
* #return A String containing a file name.
*/
public static String getFileName()
{
Scanner in = new Scanner( System.in );
String fileName;
FileReader reader;
do
{
System.out.println( "Please enter a file name to open: " );
fileName = in.nextLine();
try
{
reader = new FileReader( fileName );
}
catch( FileNotFoundException e )
{
System.out.println( "That file does not exist." );
reader = null;
}
}
while ( reader == null );
in.close();
try
{
reader.close();
}
catch ( IOException e )
{
System.out.println( e );
}
return fileName;
}
/**
* This method takes an ArrayList of Strings and prints each
* element of the ArrayList, one per line, as well as the
* number of items in the ArrayList.
*
* #param lines
*/
public static void printInformation( ArrayList<String> lines )
{
for ( String line : lines )
System.out.println( line );
System.out.println( "There are " + lines.size() + " lines in the file." );
}
public static void main( String[] args )
{
String fileName;
FileManager fileInfo;
ArrayList<String> lines = new ArrayList<String>();
fileName = getFileName( );
fileInfo = new FileManager( fileName );
try
{
lines = fileInfo.readLines();
}
catch( FileNotFoundException e )
{
System.out.println( e );
}
printInformation( lines );
}
}
This is the second class (FileManager.java):
// FileManager.java
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Scanner;
/**
* This class will manage the interaction with the
* file for the ProcessFile class.
*
*
*/
public class FileManager
{
private String fileName;
public FileManager( String file )
{
fileName = file;
}
/**
* This function will read the file stored in
* fileName and return an ArrayList made up of
* the lines of the file.
*
* #return An ArrayList containing the file's lines.
*/
public ArrayList<String> readLines( ) throws FileNotFoundException
{
ArrayList<String> lines = new ArrayList<String>();
FileReader fileIn = new FileReader( fileName );
Scanner in = new Scanner( fileIn );
while ( in.hasNextLine() )
{
String line = in.nextLine();
lines.add( line );
}
in.close();
return lines;
}
}
For the "if the user types 'Done', end the program" part, I looked up some stuff and have included it in the code below. Not sure if it is right but I got no error when I typed that part in. This are the changes I've made (I put comments by the parts I changed):
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
/**
*
* This class will ask the user for a text file
* name, open that file, and print all the lines
* of the file and how many lines there are.
*
*
*/
public class ProcessFile {
/**
* This method prompts the user to enter a
* file name and returns it.
*
* #return A String containing a file name.
*/
public static String getFileName() // Error: This method must return a result of type String
{
Scanner in = new Scanner( System.in );
String fileName;
FileReader reader;
int x = 1;
if (System.in.equals("Done") || System.in.equals("done")) // This is the part I wasn't sure of (the one I said I looked up)
{
System.exit(0);
}
else
{
while (x == 1)
{
System.out.println( "Please enter a file name to open: " );
fileName = in.nextLine();
try
{
reader = new FileReader( fileName );
}
catch( FileNotFoundException e )
{
System.out.println( "That file does not exist." );
}
in.close();
try
{
reader.close(); //Error: The local variable reader may not have been initialized
}
catch ( IOException e )
{
System.out.println( e );
}
return fileName;
}
}
}
/**
* This method takes an ArrayList of Strings and prints each
* element of the ArrayList, one per line, as well as the
* number of items in the ArrayList.
*
* #param lines
*/
public static void printInformation( ArrayList<String> lines )
{
for ( String line : lines )
System.out.println( line );
System.out.println( "There are " + lines.size() + " lines in the file." );
}
public static void main( String[] args )
{
String fileName;
FileManager fileInfo;
ArrayList<String> lines = new ArrayList<String>();
fileName = getFileName( );
fileInfo = new FileManager( fileName );
try
{
lines = fileInfo.readLines();
}
catch( FileNotFoundException e )
{
System.out.println( e );
}
printInformation( lines );
getFileName(); // <--- Return to the top and get the user input again.
}
}
I think I am close to getting this. Any bit of help would be appreciated. Thanks a lot.
**Edited Code (#µTheory)
public static String getFileName()
{
Scanner in = new Scanner( System.in );
String fileName;
FileReader reader;
do
{
System.out.println( "Please enter a file name to open: " );
fileName = in.nextLine();
if ( in.equals("Done") || in.equals("done") )
{
in.close();
System.exit(0);
}
else
{
try
{
reader = new FileReader( fileName ); //Error: The local variable reader may not have been initialized.
}
catch( FileNotFoundException e )
{
System.out.println( "That file does not exist." );
}
}
in.close();
try
{
reader.close();
}
catch ( IOException e )
{
System.out.println( e );
}
return fileName;
}
while ( reader == null );
}
So first of all, System.in refers to an InputStream so your call to System.in.equals("Done");tries to compare a Stringand an InputStreamand will obviously return false. Instead, call fileName = in.nextLine(); before your ifstatement then check if filename.equals("Done"). And put your if statement in your whileloop.
Now you have created an infinite loop : while ( x == 1) never stops because you instancied x=1and you never changes the value inside your loop.
I suggest that you change your loop to while( reader == null)as you programed before. And take out of your while statement and put them after the lines
in.close();
try
{
reader.close();//No more error
}
catch ( IOException e )
{
System.out.println( e );
}
return fileName;
So why ? Because while your reader is nullyou can not close the Scannerthat allows you to call fileName = in.nextLine(); each iteration of the loop. And as you want to end the loop when your readeris not null you can not call reader.close(); because by definition your readerobject will be null and throw a NullPointerException.
And consider before calling System.exit(0); closing all your open streams such as your Scanner.
EDIT:
public static String getFileName()
{
Scanner in = new Scanner( System.in );
String fileName;
FileReader reader;
do
{
System.out.println( "Please enter a file name to open: " );
fileName = in.nextLine();
if ( fileName.equals("Done") || fileName.equals("done") )
{
in.close();
System.exit(0);
}
else
{
try
{
reader = new FileReader( fileName ); //Error: The local variable reader may not have been initialized.
}
catch( FileNotFoundException e )
{
System.out.println( "That file does not exist." );
}
}
}
while ( reader == null );
in.close();
try
{
reader.close();
}
catch ( IOException e )
{
System.out.println( e );
}
return fileName;
}
So this the correct code. You still didn't understood that with in.equals("Done")you are trying to compare your inobejct which is an instance of Scannerand a Stringand as I said above, this will obvisouly return false. So it's why i replaced in by fileNmaewich represents the line entered by the user.
Then i extracted the block :
in.close();
try
{
reader.close();
}
catch ( IOException e )
{
System.out.println( e );
}
return fileName;
Outside of your while loop, as i stated above. You can not close the streams if you are still using them or if they are not yet instancied.
You should replace the part you are not sure about with:
if(in.nextLine().equalsIgnoreCase("done")){
System.exit(1);
}
You can do a case-insensitive comparison by using equalsIgnoreCase method.
To read from the console, just use Scanner.nextLine() or any other methods you think are suitable from the Scanner class.
If you don't want to accept input like:
"DONE", "DoNe", etc
Then just compare the input String with
"Done" and "done"
as before.
You need to get user input from Scanner and compare it with "Done", not the System.in itself. System.in is just a stream, not the actual input, and you need to read from that stream in order to compare it.
Scanner s = new Scanner(System.in)
String inp = s.nextLine()
if(inp.equals("Done"))
{
//Code
}
And, as #DeiAndrei noted in his answer, you can use equalsIgnoreCase in order to, well, compare it without case sensitivity. Forgot about that and added this for completeness.
I have some content in an input file a.txt as
Line 1 : "abcdefghijk001mnopqr hellohello"
Line 2 : "qwertyuiop002asdfgh welcometologic"
Line 3 : "iamworkingherefromnowhere002yes somethingsomething"
Line 4 : "thiswillbesolved001here ithink"
I have to read the a.txt file and write it to two separate files. ie., lines having 001 should be written to output1.txt and lines having 002 should be written to output2.txt
Can someone help me on this with a logic in Java programming.
Thanks,
Naren
BufferedReader br = new BufferedReader( new FileReader( "a.txt" ));
String line;
while(( line = br.readLine()) != null ) {
if( line.contains( "001" )) sendToFile001( line );
if( line.contains( "002" )) sendToFile002( line );
}
br.close();
The method sendToFile001() and sendToFile002() write the parameter line as follow:
ps001.println( line );
with ps001 and ps002 of type PrintStream, opened before (in a constructor?)
Here is a good example for Reading and writing text files using Java and checking conditions do the following
while ((line = reader.readLine()) != null) {
//process each line in some way
if(line.contains("001") {
fileWriter1.write(line);
} else if (line.contains("002") ) {
fileWriter2.write(line);
}
}
Code complete.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package jfile;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
/**
*
* #author andy
*/
public class JFile {
/**
* #param args the command line arguments
*/
static File master = null,
m1 = null, // file output with "001"
m2 = null; // file output with "002"
static FileWriter fw1,
fw2;
static FileReader fr = null;
static BufferedReader br = null;
public static void main(String[] args) throws FileNotFoundException, IOException
{
String root = System.getProperty("user.dir") + "/src/files/";
master = new File ( root + "master.txt" );
m1 = new File ( root + "m1.txt");
m2 = new File ( root + "m2.txt");
fw1 = new FileWriter(m1, true);
fw2 = new FileWriter(m2, true);
fr = new FileReader (master);
br = new BufferedReader(fr);
String line;
while((line = br.readLine())!=null)
{
if(line.contains("001"))
{
fw1.write(line + "\n");
} else if (line.contains("002"))
{
fw2.write(line + "\n");
}
}
fw1.close();
fw2.close();
br.close();
}
}
Project Netbeans : http://www.mediafire.com/?yjdtxj2gh785cyd
to get the content of a txt file I usually use a scanner and iterate over each line to get the content:
Scanner sc = new Scanner(new File("file.txt"));
while(sc.hasNextLine()){
String str = sc.nextLine();
}
Does the java api provide a way to get the content with one line of code like:
String content = FileUtils.readFileToString(new File("file.txt"))
Not the built-in API - but Guava does, amongst its other treasures. (It's a fabulous library.)
String content = Files.toString(new File("file.txt"), Charsets.UTF_8);
There are similar methods for reading any Readable, or loading the entire contents of a binary file as a byte array, or reading a file into a list of strings, etc.
Note that this method is now deprecated. The new equivalent is:
String content = Files.asCharSource(new File("file.txt"), Charsets.UTF_8).read();
With Java 7 there is an API along those lines.
Files.readAllLines(Path path, Charset cs)
commons-io has:
IOUtils.toString(new FileReader("file.txt"), "utf-8");
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public static void main(String[] args) throws IOException {
String content = Files.readString(Paths.get("foo"));
}
From https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/Files.html#readString(java.nio.file.Path)
You could use the FileReader class together with the BufferedReader to read the text file.
File fileToRead = new File("file.txt");
try( FileReader fileStream = new FileReader( fileToRead );
BufferedReader bufferedReader = new BufferedReader( fileStream ) ) {
String line = null;
while( (line = bufferedReader.readLine()) != null ) {
//do something with line
}
} catch ( FileNotFoundException ex ) {
//exception Handling
} catch ( IOException ex ) {
//exception Handling
}
After a bit of testing, I find BufferedReader and Scanner both problematic under various circumstances (the former often fails to detect new lines and the latter often strips spaces, for instance, from a JSON string exported by org.json library). There are other methods available but the problem is they are only supported after certain Java versions (which is bad for an Android developer, for example) and you might not want to use Guava or Apache commons library just for a single purpose like this. Hence, my solution is to read the whole file as bytes and convert it to string. The code below are taken from one of my hobby projects:
/**
* Get byte array from an InputStream most efficiently.
* Taken from sun.misc.IOUtils
* #param is InputStream
* #param length Length of the buffer, -1 to read the whole stream
* #param readAll Whether to read the whole stream
* #return Desired byte array
* #throws IOException If maximum capacity exceeded.
*/
public static byte[] readFully(InputStream is, int length, boolean readAll)
throws IOException {
byte[] output = {};
if (length == -1) length = Integer.MAX_VALUE;
int pos = 0;
while (pos < length) {
int bytesToRead;
if (pos >= output.length) {
bytesToRead = Math.min(length - pos, output.length + 1024);
if (output.length < pos + bytesToRead) {
output = Arrays.copyOf(output, pos + bytesToRead);
}
} else {
bytesToRead = output.length - pos;
}
int cc = is.read(output, pos, bytesToRead);
if (cc < 0) {
if (readAll && length != Integer.MAX_VALUE) {
throw new EOFException("Detect premature EOF");
} else {
if (output.length != pos) {
output = Arrays.copyOf(output, pos);
}
break;
}
}
pos += cc;
}
return output;
}
/**
* Read the full content of a file.
* #param file The file to be read
* #param emptyValue Empty value if no content has found
* #return File content as string
*/
#NonNull
public static String getFileContent(#NonNull File file, #NonNull String emptyValue) {
if (file.isDirectory()) return emptyValue;
try {
return new String(readFully(new FileInputStream(file), -1, true), Charset.defaultCharset());
} catch (IOException e) {
e.printStackTrace();
return emptyValue;
}
}
You can simply use getFileContent(file, "") to read the content of a file.
I have a file in a JAR file. It's 1.txt, for example.
How can I access it? My source code is:
Double result=0.0;
File file = new File("1.txt")); //how get this file from a jar file
BufferedReader input = new BufferedReader(new FileReader(file));
String line;
while ((line = input.readLine()) != null) {
if(me==Integer.parseInt(line.split(":")[0])){
result= parseDouble(line.split(":")[1]);
}
}
input.close();
return result;
If your jar is on the classpath:
InputStream is = YourClass.class.getResourceAsStream("1.txt");
If it is not on the classpath, then you can access it via:
URL url = new URL("jar:file:/absolute/location/of/yourJar.jar!/1.txt");
InputStream is = url.openStream();
You can't use File, since this file does not exist independently on the file system. Instead you need getResourceAsStream(), like so:
...
InputStream in = getClass().getResourceAsStream("/1.txt");
BufferedReader input = new BufferedReader(new InputStreamReader(in));
...
A Jar file is a zip file.....
So to read a jar file, try
ZipFile file = new ZipFile("whatever.jar");
if (file != null) {
ZipEntries entries = file.entries(); //get entries from the zip file...
if (entries != null) {
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
//use the entry to see if it's the file '1.txt'
//Read from the byte using file.getInputStream(entry)
}
}
}
Hope this helps.
Something similar to this answer is what you need.
You need to pull the file out of the archive in that special way.
BufferedReader input = new BufferedReader(new InputStreamReader(
this.getClass().getClassLoader().getResourceAsStream("1.txt")));
private String loadResourceFileIntoString(String path) {
//path = "/resources/html/custom.css" for example
BufferedReader buffer = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(path)));
return buffer.lines().collect(Collectors.joining(System.getProperty("line.separator")));
}
This worked for me to copy an txt file from jar file to another txt file
public static void copyTextMethod() throws Exception{
String inputPath = "path/to/.jar";
String outputPath = "Desktop/CopyText.txt";
File resStreamOut = new File(outputPath);
int readBytes;
JarFile file = new JarFile(inputPath);
FileWriter fw = new FileWriter(resStreamOut);
try{
Enumeration<JarEntry> entries = file.entries();
while (entries.hasMoreElements()){
JarEntry entry = entries.nextElement();
if (entry.getName().equals("readMe/tempReadme.txt")) {
System.out.println(entry +" : Entry");
InputStream is = file.getInputStream(entry);
BufferedWriter output = new BufferedWriter(fw);
while ((readBytes = is.read()) != -1) {
output.write((char) readBytes);
}
System.out.println(outputPath);
output.close();
}
}
} catch(Exception er){
er.printStackTrace();
}
}
}
I have run into this same issue several times before.
I was hoping in JDK 7 that someone would write a classpath filesystem, but alas not yet.
Spring has the Resource class which allows you to load classpath resources quite nicely.
The answers have been very good, but I thought I could add to the discussion with showing an example that works with files and directories that are classpath resources.
I wrote a little prototype to solve this very problem. The prototype does not handle every edge case, but it does handle looking for resources in directories that are in the jar files.
I have used Stack Overflow for quite sometime. This is the first time that I remember answering a question so forgive me if I go to long (it is my nature).
package com.foo;
import java.io.File;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.net.URL;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* Prototype resource reader.
* This prototype is devoid of error checking.
*
*
* I have two prototype jar files that I have setup.
* <pre>
* <dependency>
* <groupId>invoke</groupId>
* <artifactId>invoke</artifactId>
* <version>1.0-SNAPSHOT</version>
* </dependency>
*
* <dependency>
* <groupId>node</groupId>
* <artifactId>node</artifactId>
* <version>1.0-SNAPSHOT</version>
* </dependency>
* </pre>
* The jar files each have a file under /org/node/ called resource.txt.
* <br />
* This is just a prototype of what a handler would look like with classpath://
* I also have a resource.foo.txt in my local resources for this project.
* <br />
*/
public class ClasspathReader {
public static void main(String[] args) throws Exception {
/* This project includes two jar files that each have a resource located
in /org/node/ called resource.txt.
*/
/*
Name space is just a device I am using to see if a file in a dir
starts with a name space. Think of namespace like a file extension
but it is the start of the file not the end.
*/
String namespace = "resource";
//someResource is classpath.
String someResource = args.length > 0 ? args[0] :
//"classpath:///org/node/resource.txt"; It works with files
"classpath:///org/node/"; //It also works with directories
URI someResourceURI = URI.create(someResource);
System.out.println("URI of resource = " + someResourceURI);
someResource = someResourceURI.getPath();
System.out.println("PATH of resource =" + someResource);
boolean isDir = !someResource.endsWith(".txt");
/** Classpath resource can never really start with a starting slash.
* Logically they do, but in reality you have to strip it.
* This is a known behavior of classpath resources.
* It works with a slash unless the resource is in a jar file.
* Bottom line, by stripping it, it always works.
*/
if (someResource.startsWith("/")) {
someResource = someResource.substring(1);
}
/* Use the ClassLoader to lookup all resources that have this name.
Look for all resources that match the location we are looking for. */
Enumeration resources = null;
/* Check the context classloader first. Always use this if available. */
try {
resources =
Thread.currentThread().getContextClassLoader().getResources(someResource);
} catch (Exception ex) {
ex.printStackTrace();
}
if (resources == null || !resources.hasMoreElements()) {
resources = ClasspathReader.class.getClassLoader().getResources(someResource);
}
//Now iterate over the URLs of the resources from the classpath
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
/* if the resource is a file, it just means that we can use normal mechanism
to scan the directory.
*/
if (resource.getProtocol().equals("file")) {
//if it is a file then we can handle it the normal way.
handleFile(resource, namespace);
continue;
}
System.out.println("Resource " + resource);
/*
Split up the string that looks like this:
jar:file:/Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar!/org/node/
into
this /Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar
and this
/org/node/
*/
String[] split = resource.toString().split(":");
String[] split2 = split[2].split("!");
String zipFileName = split2[0];
String sresource = split2[1];
System.out.printf("After split zip file name = %s," +
" \nresource in zip %s \n", zipFileName, sresource);
/* Open up the zip file. */
ZipFile zipFile = new ZipFile(zipFileName);
/* Iterate through the entries. */
Enumeration entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
/* If it is a directory, then skip it. */
if (entry.isDirectory()) {
continue;
}
String entryName = entry.getName();
System.out.printf("zip entry name %s \n", entryName);
/* If it does not start with our someResource String
then it is not our resource so continue.
*/
if (!entryName.startsWith(someResource)) {
continue;
}
/* the fileName part from the entry name.
* where /foo/bar/foo/bee/bar.txt, bar.txt is the file
*/
String fileName = entryName.substring(entryName.lastIndexOf("/") + 1);
System.out.printf("fileName %s \n", fileName);
/* See if the file starts with our namespace and ends with our extension.
*/
if (fileName.startsWith(namespace) && fileName.endsWith(".txt")) {
/* If you found the file, print out
the contents fo the file to System.out.*/
try (Reader reader = new InputStreamReader(zipFile.getInputStream(entry))) {
StringBuilder builder = new StringBuilder();
int ch = 0;
while ((ch = reader.read()) != -1) {
builder.append((char) ch);
}
System.out.printf("zip fileName = %s\n\n####\n contents of file %s\n###\n", entryName, builder);
} catch (Exception ex) {
ex.printStackTrace();
}
}
//use the entry to see if it's the file '1.txt'
//Read from the byte using file.getInputStream(entry)
}
}
}
/**
* The file was on the file system not a zip file,
* this is here for completeness for this example.
* otherwise.
*
* #param resource
* #param namespace
* #throws Exception
*/
private static void handleFile(URL resource, String namespace) throws Exception {
System.out.println("Handle this resource as a file " + resource);
URI uri = resource.toURI();
File file = new File(uri.getPath());
if (file.isDirectory()) {
for (File childFile : file.listFiles()) {
if (childFile.isDirectory()) {
continue;
}
String fileName = childFile.getName();
if (fileName.startsWith(namespace) && fileName.endsWith("txt")) {
try (FileReader reader = new FileReader(childFile)) {
StringBuilder builder = new StringBuilder();
int ch = 0;
while ((ch = reader.read()) != -1) {
builder.append((char) ch);
}
System.out.printf("fileName = %s\n\n####\n contents of file %s\n###\n", childFile, builder);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
} else {
String fileName = file.getName();
if (fileName.startsWith(namespace) && fileName.endsWith("txt")) {
try (FileReader reader = new FileReader(file)) {
StringBuilder builder = new StringBuilder();
int ch = 0;
while ((ch = reader.read()) != -1) {
builder.append((char) ch);
}
System.out.printf("fileName = %s\n\n####\n contents of file %s\n###\n", fileName, builder);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
}
You can see a fuller example here with the sample output.