I need help on Reading and Writing files - java

I was tasked to write a program to write some websites on a text file and extract those who have the same top level domains and write it to a separate text file. This is my code:
FileWriter myWriter, comWriter, eduWriter, orgWriter, netWriter;
File newFile = new File("URL.txt");
newFile.createNewFile();
try {
myWriter = new FileWriter("URL.txt");
myWriter.write("""
yahoo.com
google.com
usl.edu
battle.net
CSU.edu
shopee.com
xyz.org
spup.edu
slideshare.net
php.net""");
myWriter.close();
System.out.println("Successfully wrote to the file!");
} catch (IOException e) {
System.out.println("Program didn't write");
}
try {
Scanner scanner = new Scanner(newFile);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (line.endsWith(".com")) {
comWriter = new FileWriter("com.txt");
comWriter.write(line);
comWriter.close();
}
if (line.endsWith(".edu")) {
eduWriter = new FileWriter("edu.txt");
eduWriter.write(line);
eduWriter.close();
}
if (line.endsWith(".net")) {
netWriter = new FileWriter("net.txt");
netWriter.write(line);
netWriter.close();
}
if (line.endsWith(".org")) {
orgWriter = new FileWriter("org.txt");
orgWriter.write(line);
orgWriter.close();
}
}
}
catch (Exception e) {
System.out.println("Error occurred");
}
My program creates new txt files. However, it only prints one line. For example, in my com.txt file it only prints "shopee.com"
Is there something that I'm missing? Improvements? Or wrongs maybe? I hope someone can help me. Thank you.

The way you are opening the files for writing always truncates the output files. If you call the FileWriter constructor with just the file name, then that file will be opened for writing and truncated.
In order to append to the file, you should use the constructor that takes a boolean argument that specifies whether you want to append or not:
comWriter = new FileWriter("com.txt", true);

You can also use Files.write method from NIO.2 instead of FileWriter:
List<String> lines = new ArrayList<>();
lines.add("yahoo.com");
lines.add("google.com");
Files.write(Paths.get("URL.txt"), lines);
Or
Files.write(Paths.get("URL.txt"), lines, StandardOpenOption.APPEND);
if you want to append to existing file.
Optionally you can create a list of lines like this:
List<String> lines = List.of("yahoo.com", "google.com");
The file is closed when all lines have been written automatically.

There are so many ways this sort of thing can be done. Here is one example using Java's NIO:
Creating the URL List file:
List<String> urlList = Arrays.asList(new String[] {"yahoo.com", "google.com", "usl.edu",
"battle.net", "CSU.edu", "shopee.com", "xyz.org", "spup.edu",
"slideshare.net", "php.net"});
try {
java.nio.file.Files.write(java.nio.file.Paths.get("URL.txt"),
urlList, java.nio.charset.StandardCharsets.UTF_8);
System.out.println("Successfully created the URL.txt file!");
}
catch (IOException ex) {
System.err.println("Error creating the URL.txt file!" +
System.lineSeparator() + ex.getMessage());
}
Reading the URL List file and creating Top-Level Domain (TLD) files:
/*
Creates Top-Level Domain (TLD) files that will store respective Domain Name Strings.
Returns a comma (,) delimited string containing the Number of TLD files created and
the number of Domain Name Strings added to the various TLD files created (in that
order).
Output to console can be commented out or removed from this method.
If the supplied source path does not exist then an 'IllegalArgumentexception' is
thrown.
If the supplied destination path does not exist then there will be an attempt to
create it.
*/
public static String createTopLevelFiles(String sourcePath, String destinationPath) {
// Does Source file exist? Throw exception if not.
sourcePath = sourcePath.replace("\\\\",File.separator).replace("\\",File.separator);
if (!java.nio.file.Files.exists(java.nio.file.Paths.get(sourcePath))) {
// No...
throw new IllegalArgumentException("createTopLevelFiles() Method Error!"
+ "Source file can not be found! (" + sourcePath + ")");
}
// Read Source file domains content into a List Interface Oject:
// =============================================================
List<String> urlList = null;
try {
java.nio.file.Path path = java.nio.file.Paths.get(sourcePath);
urlList = java.nio.file.Files.readAllLines(path, java.nio.charset.StandardCharsets.UTF_8);
if (urlList == null || urlList.isEmpty()) {
System.err.println("createTopLevelFiles() Method Warning! No Domains "
+ "available within URL List source file!");
return null; // Exit with null due to failure;
}
}
catch (IOException ex) {
System.err.println("createTopLevelFiles() Method Error!"
+ System.lineSeparator() + ex.getMessage());
return null; // Exit with null due to failure;
}
// =============================================================
// Check Destination Path - Create it if it doesn't already exist:
// =============================================================
destinationPath = destinationPath.replace("\\\\",File.separator).replace("\\",File.separator);
java.nio.file.Path destPath = java.nio.file.Paths.get(destinationPath);
if (!java.nio.file.Files.exists(destPath)) {
try {
// Creating the new directory because it doesn't exist in local system.
Files.createDirectories(destPath);
// System.out.println("Destination Directory Successfully Created!");
}
catch (IOException ex) {
System.err.println("Problem Occured While Creating The Destination "
+ "Directory!" + System.lineSeparator() + ex.getMessage());
return null; // Exit with null due to failure;
}
}
// =============================================================
// Create the Top-Level Domain files:
// =============================================================
int fileCount = 0; // Keep count of TLD file creations.
int failCount = 0; // Keep count of Saved Domain Name failures.
for (String domain : urlList) {
String fileName = domain.substring(domain.lastIndexOf(".") + 1) + ".txt";
String filePath = new StringBuilder(destinationPath)
.append(File.separator).append(fileName)
.toString().replace("\\\\",File.separator)
.replace("\\",File.separator);
try {
java.nio.file.Path fPath = java.nio.file.Paths.get(filePath);
// If the file doesn't already exist then create it...
if (!java.nio.file.Files.exists(fPath)) {
java.nio.file.Files.createFile(fPath);
System.out.println("Successfully created the \"" +
filePath.substring(filePath.lastIndexOf(File.separator) + 1)
+ "\" TLD file!");
fileCount++;
}
// Is the domain name already in file? if so ignore it.
List<String> tmpList = null;
tmpList = java.nio.file.Files.readAllLines(fPath, java.nio.charset.StandardCharsets.UTF_8);
if (tmpList.contains(domain)) {
tmpList.clear();
failCount++;
continue;
}
// Append the domain name String to file...
java.nio.file.Files.write(fPath, (domain + System.lineSeparator()).getBytes(java.nio.charset.StandardCharsets.UTF_8),
java.nio.file.StandardOpenOption.APPEND);
System.out.println("Successfully added the \"" + domain + "\" domain name to the '"
+ filePath.substring(filePath.lastIndexOf(File.separator) + 1)
+ "' TLD file!");
}
catch (IOException ex) {
failCount++;
System.err.println("WARNING - Error creating the " +
filePath.substring(filePath.lastIndexOf(File.separator) + 1) +
" file! | " + ex.getMessage());
}
}
// =============================================================
// Failure results (delete this code if you like).
// =============================================================
if (failCount > 0) {
System.err.println(failCount + " out of " + urlList.size() +
" domain names failed to be added!");
System.err.println("This could be due to the fact that the domain");
System.err.println("name is already stored or, one or more domain");
System.err.println("names were found to be invalid.");
}
// =============================================================
/* Return the total number of TLD files created and
the total number of domain names added to these
various TLD files. */
return new StringBuilder(String.valueOf(fileCount)).append(", ")
.append(String.valueOf((urlList.size() - failCount))).toString();
}
The method above will automatically create the destination path (directory path) within the local file system if it doesn't already exist and it automatically determines the file names required to create into that destination path based on the TLD domain name attached to each domain name string. Domain name strings are appended to their respective file once that file is created. If a Domain Name is already contained within a TLD file then that name is ignored and 1 is added to the failure count.
Read all comments in code.
Usage Example:
String result = createTopLevelFiles("URL.txt", "D:\\Top-Level_Domains");
System.out.println();
System.out.println("Result is: " + result);
Console output example:
Successfully created the "com.txt" TLD file!
Successfully added the "yahoo.com" domain name to the 'com.txt' TLD file!
Successfully added the "google.com" domain name to the 'com.txt' TLD file!
Successfully created the "edu.txt" TLD file!
Successfully added the "usl.edu" domain name to the 'edu.txt' TLD file!
Successfully created the "net.txt" TLD file!
Successfully added the "battle.net" domain name to the 'net.txt' TLD file!
Successfully added the "CSU.edu" domain name to the 'edu.txt' TLD file!
Successfully added the "shopee.com" domain name to the 'com.txt' TLD file!
Successfully created the "org.txt" TLD file!
Successfully added the "xyz.org" domain name to the 'org.txt' TLD file!
Successfully added the "spup.edu" domain name to the 'edu.txt' TLD file!
Successfully added the "slideshare.net" domain name to the 'net.txt' TLD file!
Successfully added the "php.net" domain name to the 'net.txt' TLD file!
Result is: 4, 10
4 TLD files created in destination path and 10 domain names were added to those files.

Related

Pick a particular file from directory using java

I need some help in picking the exact file from directory on Windows using Java. Below is the code which I have written for this. But when I pass my input as "XYZ" file it always picks the "ABC" file only.
My input to pick the file was 'XYZ', but output always returns 'ABC' file
directoryPath = new File(System.getProperty("user.dir") + "\\TestFilesDirectory\\");
String contents[] = directoryPath.list();
System.out.println("List of files and directories in the specified directory : " + directoryPath);
for (int i = 0; i < contents.length; i++) {
// System.out.println(contents[i]);
ArrayList<String> fileNameList = new ArrayList<String>();
String[] fileNameSplit = contents[i].split("_");
for (int k = 0; k < fileNameSplit.length; k++) {
// System.out.println(fileNameSplit[k].toUpperCase());
fileNameList.add(fileNameSplit[k].toUpperCase());
}
if (fileNameList.contains("ABC") {
System.out.println("Pick ABC file from directory ");
source = new File(directoryPath + "\\" + contents[i] + "");
}
System.out.println("Base File: " + source);
else if (fileNameList.contains("DEF") {
System.out.println("Pick DEF file from directory ");
source = new File(directoryPath + "\\" + contents[i] + "");
}
else if (fileNameList.contains("XYZ") {
System.out.println("Pick XYZ file from directory ");
source = new File(directoryPath + "\\" + contents[i] + "");
}
Below are my files in Test directory:
I think that your code can be improved. As far as I can tell you need to retrieve the path of a given file matching either the first or second part of its filename. So for example:
DEF_GHI.txt
can be matched by either inputting def or ghi into your search method. The easiest and most concise way to do so would be:
public Optional<File> findByName(String name, String directoryPath) {
try (var fileStream = Files.list(Path.of(directoryPath))) {
return fileStream
.filter(path -> Arrays.stream(path.getFileName().toString().split("_"))
.map(part -> part.replaceAll("\\.[^.]*$", ""))
.anyMatch(part -> part.equalsIgnoreCase(name)))
.findAny()
.map(Path::toFile);
} catch (IOException e) {
System.err.println("Unable to open directory stream for path:: " + directoryPath);
e.printStackTrace();
}
return Optional.empty();
}
What this does is the following:
Accepts a filename and a path representing a directory to search at
Creates a stream of paths representing the files under the given directory
Gets the filename for each given path and performs the following:
Splits the string using _ in order to retrieve both parts (if present)
Replaces everything after the . character (including it) in order to get rid of the file extension.
Attempts to match each part against the provided name parameter
Map the found path value to a File (if present)
Lastly returns either the optionally wrapped File or an empty Optional.
I hope this is what you are looking for.

Unable to move file using renameTo()

I currently have a file monitor, which reads an XML file and updates database tables base on the contents. When a file is read it is validated against a specific schema to ensure the contents are correct.
The result of the validation effects the destination of the file to move.
If the schema is successful, there are no issues when moving the file to the processed directory, however, when the schema fails I am unable to rename the file itself.
However, when I debug and explore the file paths to ensure the file is being moved to the right location, it often allows me to rename the file which makes me think this is a timing issue.
File Monitor Class :
// Get a directory listing;
FilterFiles filterFiles = new FilterFiles();
String inbox = GlobalVars.getConfiguration().getInboundInbox();
String [] dir = new File(inbox).list(filterFiles);
// Wait 500 ms before obtaining files (Avoid the ResourceBusy error);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// Log errors
logger.info("Interrupted Exception " + e.getMessage());
new LogStackTrace(logger, e);
e.printStackTrace();
}
// Iterate through directory;
for ( int a=0; a < dir.length; a++ ) {
// Derive the full file path i.e. folder + path name;
String fullFilePath = GetAbsoloutePath.getFullAbsoluteFilePath(inbox, dir[a]);
logger.info("==========================================================");
logger.info("");
logger.info("Found File : " + fullFilePath);
logger.info("==========================================================");
// Does the file exist & can we read the file at this time;
File file = new File(fullFilePath);
if (file.exists() && file.canRead()) {
// Process the file;
StringBuffer renamedFile = new StringBuffer();
// Rename the file to indicate InProgess;
String fileName = file.getAbsolutePath();
String fileNameInProgress = fileName.trim() + ".InProgress";
// Delete the file if exists where we are moving the file to;
File deleteFile = new File(fileNameInProgress);
if (deleteFile.delete()) logger.info("Existing file deleted: " + fileNameInProgress);
// Ensure file is renamed so we can see it is in progress
if (!file.renameTo(new File(fileNameInProgress)) ) {
// Logging
logger.error("Failed to renamed file :" + fileName + " to " + fileNameInProgress);
break;
}else{
logger.info("Renamed file to : " + fileNameInProgress);
// Pass back name of renamed file;
renamedFile.append(fileNameInProgress);
File renamedFileRef = new File(renamedFile.toString());
// Path to move - could be errors or processed
String pathToMove = "";
// Parse XMobject
ParseInboundXML par = new ParseInboundXML();
// check if parse was succesful
if(par.parseXML(renamedFileRef, con)){
// Path to move XML file
pathToMove = GlobalVars.getConfiguration().getInboundProcessed()+ "\\" + file.getName();
//Logging
logger.info("File parsed and tables updated successfully");
logger.info("Moving file to : " + pathToMove);
}else{
pathToMove = GlobalVars.getConfiguration().getInboundErrors()+ "\\" + file.getName();
//Logging
logger.error("Errors when parsing file and updating tables");
logger.error("Moving file to : " + pathToMove);
}
// Help with garbage collection
par = null;
// New file
File newPath = new File(pathToMove);
// Need to check if this already exists in processed- if so we must override the existing file
// Otherwise the move will not be processed and the same docuemnt will be continously processed
if(newPath.exists())
newPath.delete();
After the above code has been executed, this block of code is executed and this is where the rename fails:
// Rename path so it is placed in processed folder
if(renamedFileRef.renameTo(newPath)){
//Logging
logger.info("File processed successfully");
}else{
// Logging
logger.error("Unable process file");
}
Within the code you may notice the call to :
// Parse XMobject
ParseInboundXML par = new ParseInboundXML();
// check if parse was succesful
if(par.parseXML(renamedFileRef, con)){
This method is where the validation occurs and the parsing of the XML document and returns a true or false value depending on the outcome.
The area in which it fails is at the start of the method :
// Find schema path
String schemaPath = GlobalVars.getConfiguration().getInboundSchemaLocation();
String schemaFileName = "WMS_" + file.getAbsoluteFile().toString().split("#")[2] + ".xsd";
// Schema location
String schemaLocation = schemaPath + "\\" + schemaFileName;
// Create schema factory
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
// Schema file
Source schemaFile = new StreamSource(new File(schemaLocation));
// Apply schema and validate XML
Schema schema = schemaFactory.newSchema(schemaFile);
Validator validator = schema.newValidator();
Source xmlFile = new StreamSource(file);
validator.validate(xmlFile);
I think the issue may lie around
Source xmlFile = new StreamSource(file);
as this is the file we try to rename, and i think if it fails validation, its possible that this may be keeping the file open and would explain why there are no issues when it passes validation.
EDIT
This is the catch clause for a failed validation:
catch (SAXException e) {
// Write Error Record
CreateErrorMessages.createIW702Message(record.getTrno701TransactionNumber(), IntegrationConstants.SAX_ERROR, "SAX Error", e.toString(), con);
// Logging
logger.info("SAX Exception " + e.getMessage());
// Log stack trace
new LogStackTrace(logger, e);
// Prints to stack trace
e.printStackTrace();
return false;
}
If you want to later rename the file, it has to be closed first. Apparently, your code does not do that.
Closing StreamSource and Moving files after failed validation (Java) suggest to not pass in a File but instead a FileInputStream that you can then close at the end yourself (or use try-with-resource)
try(InputStream in = new FileInputStream (file)) {
Source xmlFile = new StreamSource(fr);
validator.validate(xmlFile);
}

Zip4j missing the last file added

I'm trying to zip a bunch of files using the Zip4j library. I pass a list of the file paths of the files I want to compress and I add them one by one into the zip file. For some reason, the last file does not get added. I checked the indexes of the loop and I'm pretty sure they're correct. I am not getting any exceptions or error messages. Here's my code:
// get the path; paths refers to the list of files to compress
String uuidString = UUID.randomUUID().toString();
String path = "H:/public/ZipFiles/" + uuidString + ".zip";
try {
// create the new zip file
ZipFile zipFile = new ZipFile(path);
File fileToAdd;
String message = "";
ZipParameters parameters = new ZipParameters();
// set compression method to store compression
parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
// Set the compression level
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
// add each file to the zipFile
for(int i = 0; i < paths.size(); i++)
{
fileToAdd = new File(paths.get(i));
if(fileToAdd.exists())
{
System.out.println("writing file at " + paths.get(i) + " to the zip file");
zipFile.addFile(fileToAdd, parameters);
}
else
{
message += "File with at path " + paths.get(i) + " was not found.\n";
}
}
} catch (ZipException e) {
e.printStackTrace();
}
All the file paths get printed when they are added. Any ideas?
You're not closing the ZipFile.
I think there is a problem with the jar file from their own website at http://www.lingala.net/zip4j/download.php
But when I downloaded it from the maven repository at https://mvnrepository.com/artifact/net.lingala.zip4j/zip4j/1.3.2 , it is working perfectly.

IO file attributes

import java.io.File;
class AttriDemo{
public static void main(String args[]){
File f1 = new File("FileIO/file.txt");
System.out.println("File name : " + f1.getName());
System.out.println("File path : " + f1.getPath());
System.out.println("File AbsPath : " + f1.getAbsolutePath());
System.out.println("File parent : " + f1.getParent());
f1.setWritable(true);
if(f1.canWrite())
{
System.out.println("File is Writeable");
}
else
{
System.out.println("File is not Writeable");
}
if(f1.canRead())
{
System.out.println("Is readable");
}
else
{
System.out.println("File is not readable");
}
}
}
I the file is readable and writable in real...
then I tried setting it to Writable explicitly but still the output shows it as the file is not writable!!
output:
....
The file is not writable.
The file is not readable.
File f1 = new File("D:/javaProgs/FileIO/AttriDemo.java");
doing this helps solve the problem.
but can someone explain how? I mean the file was in the same directory and the statements above were running just fine. e.g getName() getParent()
What's fooling you is you can create a File object regardless of the path you specified exists or not and you can call all those getParent, getPath functions on that object.
You can create a File object that's not backed by a real file for various reasons like to check if it exists or to create a file specified by that objects path and name.
You can use File.exists() to see if file really exists on file system.

Creating a directory within another directory in user.home?

I was just wondering if the code I made will work to create multiple directories within each other. I used this as a reference.
String username = enterUserTF.getText(); //the username the user enters in a textfield.
boolean myGamesFolderSuccess = new File(System.getProperty("user.home"), "My Games").mkdir();
boolean mainFolderSuccess = new File("My Games", "Type King").mkdir();
boolean userSuccess = new File("TypeKing", username).mkdir(); //creates a folder with the users username.
if(myGamesFolderSuccess){
if(mainFolderSuccess){
if(userSuccess){
System.out.println("Directory " + username + " created.");
File f = new File(username + "/test.txt");
if(!f.exists()){
try {
f.createNewFile();
} catch (IOException e) {
e.printStackTrace();
System.out.println("Could not create user's file.");
}
}
}
}
}
}
So to sum up the above, I made the the first directory "My Games" in user.home, then placed my game's name, "Type King" in that directory, and whenever the user enters a username, I want a directory to be created that is their username. File f just checks for a file in the username directory.
It is recommended to use the mkdirs method of the File class instead of checking multiple status flags when creating nested directories. Also, never use concatenation for creating File objects/paths.
Also, if you want your game to be portable, make sure you don't have special characters in your directory names like a space etc.Why are you asking user for the name instead of retrieving it from user.name system property? Something like this should work:
String username = System.getProperty("user.name");
File myGamesDir = new File(System.getProperty("user.home"), "my-games");
File typeKingDir = new File(myGamesDir, "type-king");
File userDir = new File(typeKingDir, username);
boolean userSuccess = userDir.mkdirs();
if(userSuccess){
System.out.println("Directory " + username + " created.");
File f = new File(userDir, "test.txt");
if(!f.exists()){
try {
f.createNewFile();
} catch (IOException e) {
e.printStackTrace();
System.out.println("Could not create user's file.");
}
}
}
 
If you pass a full path to File.mkdirs (with an s) it will make an arbitrarily deep directory structure. You don't have to build paths one directory at a time. If the directories already exist, or if some of them exist, it will still work as you expect.
import java.io.File;
import javax.swing.JOptionPane;
class Dirs {
public static void main(String[] args) throws Exception {
String subDir = "My Games|Type King";
String userName = JOptionPane.showInputDialog(
null,
"Who are you?");
subDir += "|" + userName;
String[] parts = subDir.split("\\|");
File f = new File(System.getProperty("user.home"));
for (String part : parts) {
f = new File(f, part);
}
boolean madeDir = f.mkdirs();
System.out.println("Created new dir: \t" + madeDir + " \t" + f);
f = new File(f, "eg.txt");
if (!f.exists()) {
boolean madeFile = f.createNewFile();
System.out.println(
"Created new file: \t" + madeFile + " \t" + f );
}
}
}
Output
Created new dir: true C:\Users\Andrew\My Games\Type King\BilboBaggins
Created new file: true C:\Users\Andrew\My Games\Type King\BilboBaggins\eg.txt
I think its better to use existing functionality available in the API. If you don't have any restrictions consider switching to the latest JDK. In 1.7 Oracle did introduce so many enhancements including IO and New IO.
For creating multiple directories within each other you can take advantage of Files.createDirectories available since 1.7. "It will create a directory by creating all nonexistent parent directories first."

Categories

Resources