This question already has answers here:
Reading a plain text file in Java
(31 answers)
Closed 4 years ago.
I have created a class that has the features of reading and writing to a file even parsing what is in the file. But when I run my test, I am not able to read the file. This is the snippet of what I have, if it is not enough I can post the rest of what I have to help.
this is what my main looks like:
public static void main(String args[]) throws IOException {
String fileLocation = File.separator + "Users" + File.separator + "Desktop" + File.separator + "test.txt";
File file = new File(fileLocation);
DataStorage data = new DataStorage(fileLocation);
data.read();
}
this is what my read method looks like:
public File file;
public DataStorage(String filePath) {
setFile(filePath);
}
public Data read() throws IOException {
Data db = new Data();
Scanner scan = new Scanner(file);
Person person;
//check if file has data print selected data
while(scan.hasNextLine()) {
person = parsePerson(scan.nextLine());
db.add(person);
}
if(scan != null) {
// close() may throw IOException if fails;
scan.close();
}
return db;
}
Instead of filePath, you need to pass the file object as an Argument and the path which you are sending is incorrect in the main method "C DRIVE IF WINDOWS" otherwise starts with \ i.e, File.separator for Mac
public class Stackex1 {
public static void main(String args[]) throws IOException {
String fileLocation = "C:"+ File.separator + "Users" + File.separator + "USERNAMEGOESHERE" + File.separator + "Desktop" + File.separator + "test.txt";
System.out.println(fileLocation);
File file = new File(fileLocation);
DataStorage data = new DataStorage(file);
data.read();
}
}
class DataStorage {
public File file;
public DataStorage(File file) {
setFile(file);
}
public void setFile(File file) {
this.file = file;
}
.... //Remaining code goes here
Note: I am aware there are several questions similar to this one, however, I cannot find any which explain how to resolve the situation I am trying to resolve. I will ask this question with a specific example, for which I need a solution.
Consider the code:
private final void writeToFile(final File parent, final String filename, final Charset charset, final String content) throws IOException {
final File file = new File(parent, filename);
if (file.exists()) {
LOG.warn("File {} already exists, file will be replaced.", file.getCanonicalPath());
if (!file.delete()) {
logAndThrow(String.format("Cannot delete file '%s'.", file.getCanonicalPath()), null);
}
}
try (final FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter writer = new OutputStreamWriter(fos, charset)) {
writer.write(content);
}
}
I am trying to write a unit test to provoke the IOException being thrown when the code cannnot delete the file. The unit test I have tried is as follows:
#Test public void testFileNotDeletable() throws IOException {
final File file = new File(folder.getRoot(), formattedFile.getMetaData().getFormattedCaptureFileName());
file.createNewFile();
try {
file.setReadOnly();
exception.expect(IOException.class);
exception.expectMessage(String.format("Cannot delete file '%s'.", file.getCanonicalPath()));
writer.write(formattedFile);
} finally {
file.setWritable(true);
}
}
I have also tried locking the file:
#Test public void testFileNotDeletable() throws IOException {
final File file = new File(folder.getRoot(), formattedFile.getMetaData().getFormattedCaptureFileName());
file.createNewFile();
try (FileInputStream fis = new FileInputStream(file)) {
final FileLock lock = fis.getChannel().tryLock(0L, Long.MAX_VALUE, true);
try {
exception.expect(IOException.class);
exception.expectMessage(String.format("Cannot delete file '%s'.", file.getCanonicalPath()));
writer.write(formattedFile);
} finally {
lock.release();
}
}
}
No matter what I try, the file.delete() successfully deletes the file, and the test fails, as the expected IOException was not thrown.
Any help greatly appreciated.
Note: Added for clarification, some extra code that shows that the File object is completely separate in the environments. The formattedFile being passed to the write method is not a File or sub-class of File, it is one of our internal classes. The File in the JUnit test is using a TemporaryFolder for the root, the formattedFile has a MetaData item, which determines the filename. In my JUnit test I am trying to create an empty file, which cannot be deleted, in the location that my actual code will attempt to write the file. I need file.delete() to return false, so that I can test the exception is being thrown. I therefore cannot mock a File object.
There are two solutions to your question, I recommend the first one.
Solution 1
You are not testing the java file I/O operations/class here, you are testing your code's functional behaviour in response to file operation. So, ideally in your JUnit you should be mocking the File object & its respective calls, and only focus on testing your code.
Solution 2
If you still wish to test full integration with java file IO, open file in write mode before attempting to delete, and it will take care of your test case.
NOTE: Code tested in CENTOS, WINDOWS, UBUNTU, MAC OS-X
Subject Class:
public class FileSolution {
public void fileHandler(File file) throws IOException, Exception {
if (file.exists()) {
LOG.warn("File {} already exists, file will be replaced.",
file.getCanonicalPath());
if (!file.delete()) {
logAndThrow(String.format("Cannot delete file '%s'.",
file.getCanonicalPath()),
new IOException(String.format("Cannot delete file '%s'.",
file.getCanonicalPath())));
}
}
}
}
Subject Uner Test:
import static org.mockito.BDDMockito.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class FileSolutionTest {
#Rule
public final ExpectedException exception = ExpectedException.none();
/**
* Solution 1
*
* #throws Exception
*/
#Test
public void testFileNotDeletableWithMock() throws Exception {
final File file = mock(File.class);
file.createNewFile();
// mock file & IO operations
given(file.exists()).willReturn(true);
given(file.delete()).willReturn(false);
given(file.getCanonicalPath()).willReturn("test.txt");
exception.expect(IOException.class);
exception.expectMessage(String.format("Cannot delete file '%s'.", file.getCanonicalPath()));
new FileSolution().fileHandler(file);
}
/**
* Solution 2
*
* #throws Exception
*/
#Test
public void testFileNotDeletable() throws Exception {
File file = null;
FileWriter fileWriter = null;
try{
file = new File("test.txt");
file.createNewFile();
file.deleteOnExit();
exception.expect(IOException.class);
exception.expectMessage(String.format("Cannot delete file '%s'.", file.getCanonicalPath()));
// open file with another process for writing
fileWriter = new FileWriter(file, true);
new FileSolution().fileHandler(file);
} finally{
if(fileWriter != null){
fileWriter.flush();
fileWriter.close();
}
}
}
}
I totally agree with Turing85 about using mockito.
Let's imagine you have an original class with a method similar to the one you want to test:
public class FileDel {
public void logOnIOException(File file) throws IOException {
if (file.exists()) {
LOG.warn("File {} already exists, file will be replaced.", file.getCanonicalPath());
if (!file.delete()) {
logAndThrow(String.format("Cannot delete file '%s'.", file.getCanonicalPath()), null);
}
}
}
public void logAndThrow(String msg, String s) {
//Do nothing
}
private static class LOG {
public static void warn(String msg, String path) {
}
}
}
Then you can trigger an inner exception in this way:
#RunWith(MockitoJUnitRunner.class)
public class FileDelTest {
#Test(expected = IOException.class)
public void testFileNotDeletable() throws IOException {
File file = mock(File.class);
when(file.exists()).thenReturn(true);
when(file.delete()).thenAnswer(new Answer<Boolean>() {
#Override
public Boolean answer(InvocationOnMock iom) throws Throwable {
throw new IOException();
}
});
FileDel f = new FileDel();
try {
f.methodToTest(file);
} finally {
}
}
}
What about open InputStream for this file and do not close it. Until file's descriptor will not be closed, file will not be deleted.
In order to prevent a file from being deleted you have to deny the security permission in windows. From the UI we would need to do something like
Right-click the file or document in your PC => Choose Properties;
In Security, tab Edit to change permission => Select Add and enter Everyone;
Press OK and select the group to change Full control permission to Deny;
Press Yes to confirm.
The only way I know of to change file permissions with Java are:
file.setExecutable(true|false);
file.setReadable(true|false);
file.setWritable(true|false);
and
File file = new File("test.txt");
if(file.exists())
{
//Setting file permissions for owner, group and others using PosixFilePermission
HashSet<PosixFilePermission> set = new HashSet<PosixFilePermission>();
//Adding owner's file permissions
set.add(PosixFilePermission.OWNER_EXECUTE);
set.add(PosixFilePermission.OWNER_READ);
set.add(PosixFilePermission.OWNER_WRITE);
//Adding group's file permissions
set.add(PosixFilePermission.GROUP_EXECUTE);
set.add(PosixFilePermission.GROUP_READ);
set.add(PosixFilePermission.GROUP_WRITE);
//Adding other's file permissions
set.add(PosixFilePermission.OTHERS_EXECUTE);
set.add(PosixFilePermission.OTHERS_READ);
set.add(PosixFilePermission.OTHERS_WRITE);
Files.setPosixFilePermissions(Paths.get("test.txt"), set);
}
else
{
System.out.println("Sorry...File doesn't exist.");
}
So, preventing a file from being deleted I would assume would have to do with file writing permissions. Try disabling the writable and maybe the executable permissions before trying to delete the file.
If this doesn't work then I do not believe it can be done with the Java language yet as these are the only methods available at the moment for changing file permissions. I could be wrong, but I have been unable to find anything else.
UPDATE
For Linux try the following:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ExecuteShellComand {
public static void main(String[] args) {
ExecuteShellComand obj = new ExecuteShellComand();
String command = "sudo chattr +i /backups/passwd";
// OR try
//String command = "sudo chattr +i -V /backups/passwd";
String output = obj.executeCommand(command);
System.out.println(output);
}
private String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
}
The above makes /backups/passwd file immutable (or undeletable). This implies that the file can’t be modified in any way: it can’t be deleted or renamed. You can’t even create a link to it and no data can be written to the file as well.
That's about the only thing I can think of.
Hope this helps.
In Linux you can, with the chattr command set a file that is "immutable" that cannot be deleted even by root. Someone else said "set file permissions" which is right, but did not give specific detail.
Cheers
D
I am trying to write code for a word guessing game, and it works well when I use bufferedreader and inputstream combined. But when I try it using scanner, it cannot find the file, even though in both instances the file is in the same folder. It is in a folder called res under the src folder in my project folder(I am coding in eclipse).
import java.util.ArrayList;
import java.util.Scanner;
import java.io.File;
public class WordGen {
private final String filename = "/res/words.txt";
File file = new File(filename);
Scanner input = null;
private ArrayList<String> list = new ArrayList<>();
public WordGen() {
try {
input = new Scanner(file);
while (input.hasNextLine()) {
String w = input.nextLine();
list.add(w);
}
} catch (Exception ex) {
System.out.println("File not found.");
}
}
public String getword() {
if (list.isEmpty()) {
return "NOTHING";
}
return list.get((int) (Math.random() * list.size()));
}
}
public class test {
public static void main(String[] args) {
WordGen wordgen = new WordGen();
System.out.println(wordgen.getword());
}
}
I tried searching for this problem but couldn't find it here. I am guessing it's a very small error which I cannot figure out. Thanks and regards.
EDIT: Here's the other code that worked(Everything else same as before):
public WordGenerator()
{
try(InputStream input = getClass().getResourceAsStream(fileName);
BufferedReader bfreader = new BufferedReader(new InputStreamReader(input)))
{
String line = "";
while ((line = bfreader.readLine()) != null)
words.add(line);
}
catch (Exception e)
{
System.out.println("Couldn't find file");
}
}
Scanner is trying to load a file - and you're providing an absolute filename, /res/words.txt.
In order to create an InputStream, you're loading a resource, giving it an absolute resource name, even though you've called the variable fileName:
getClass().getResourceAsStream(fileName)
That works because it can load a resource called /res/words.txt from the classpath, but it's not loading a file with a filename of /res/words.txt.
You could use a filename of res/words.txt, if you run the code from the src directory... or you could just stick to using getResourceAsStream, which is probably a better idea as it doesn't rely on your working directory, and will continue to work even if your code and resources are packaged up into a jar file.
If you really want to use Scanner, you could always use new Scanner(input) - there's a Scanner constructor accepting an InputStream.
I'm trying to read from a .txt file that is located in src\main\java\props\engprops.txt. I'm using backslashes here because I'm using Windows.
When I try to read the file I get a FileNotFoundException.
This is my helper class. It contains a method for returning a string representation of the directory in which the file is located. Here is what it returns C:\Users\SOME_USER\workarea\Myapp\myapp\src\main\props\
private final static String APP_HOME = "\\workarea\\Translate\\translate\\src\\main";
private final static String PROPS_HOME = "\\props\\";
public static String getPropsPath() {
StringBuilder sb = new StringBuilder();
String userHome = System.getProperty("user.home");
//userHome = userHome.replace("\\", "/");
String propsHome = null;
propsHome = userHome + APP_HOME + PROPS_HOME;
return propsHome;
}
Then in my main class is where I try to read the file:
private static String stringPath = AppHelper.getPropsPath();
public static void main(String[] args) {
readFile();
}
public static void readFile() throws IOException {
FileReader fReader = new FileReader(stringPath + "engprops.txt");
BufferedReader bReader = new BufferedReader(fReader);
String line = null;
while((line = bReader.readLine()) != null) {
System.out.println(line);
}
bReader.close();
}
Inside the readFile() method, I am appending the name of the file on to the stringPath variable with the file name being engprops.txt.
Here is a snippet of the console displays after the program executes; java.io.FileNotFoundException: C:\Users\600010209\workarea\Translate\translate\src\main\props\engprops.txt (The system cannot find the file specified)
You wrote in your question that your file was located under src/main/java/props, but the props path you declared was under src/main/props.
Comment if that doesnt answer your question.
I am trying to extract an archive .tar.gz using java and I am getting Directory error that I do not seem to understand. Please help. I got this sample code from https://forums.oracle.com/forums/thread.jspa?threadID=2065236
package untargz;
import java.io.*;
import com.ice.tar.*;
import javax.activation.*;
import java.util.zip.GZIPInputStream;
/**
*
* #author stanleymungai
*/
public class Untargz {
public static InputStream getInputStream(String tarFileName) throws Exception{
if(tarFileName.substring(tarFileName.lastIndexOf(".") + 1, tarFileName.lastIndexOf(".") + 3).equalsIgnoreCase("gz")){
System.out.println("Creating an GZIPInputStream for the file");
return new GZIPInputStream(new FileInputStream(new File(tarFileName)));
}else{
System.out.println("Creating an InputStream for the file");
return new FileInputStream(new File(tarFileName));
}
}
private static void untar(InputStream in, String untarDir) throws IOException {
System.out.println("Reading TarInputStream... ");
TarInputStream tin = new TarInputStream(in);
TarEntry tarEntry = tin.getNextEntry();
if(new File(untarDir).exists()){
while (tarEntry != null){
File destPath = new File(untarDir + File.separatorChar + tarEntry.getName());
System.out.println("Processing " + destPath.getAbsoluteFile());
if(!tarEntry.isDirectory()){
FileOutputStream fout = new FileOutputStream(destPath);
tin.copyEntryContents(fout);
fout.close();
}else{
destPath.mkdir();
}
tarEntry = tin.getNextEntry();
}
tin.close();
}else{
System.out.println("That destination directory doesn't exist! " + untarDir);
}
}
private void run(){
try {
String strSourceFile = "C:/AskulInstaller/pid.tar.gz";
String strDest = "C:/AskulInstaller/Extracted Files";
InputStream in = getInputStream(strSourceFile);
untar(in, strDest);
}catch(Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
}
public static void main(String[] args) {
new Untargz().run();
}
}
Once I run this piece of code, this is My Output;
Creating an GZIPInputStream for the file
Reading TarInputStream...
That destination directory doesn't exist! C:/AskulInstaller/Extracted Files
BUILD SUCCESSFUL (total time: 0 seconds)
When I Manually Create the destination Directory C:/AskulInstaller/Extracted Files
I get this Error Output;
Creating an GZIPInputStream for the file
Reading TarInputStream...
Processing C:\AskulInstaller\Extracted Files\AskulInstaller\pid\Askul Logs\DbLayer_AskulMain_10_Apr_2013_07_44.log
java.io.FileNotFoundException: C:\AskulInstaller\Extracted Files\AskulInstaller\pid\Askul Logs\DbLayer_AskulMain_10_Apr_2013_07_44.log (The system cannot find the path specified)
C:\AskulInstaller\Extracted Files\AskulInstaller\pid\Askul Logs\DbLayer_AskulMain_10_Apr_2013_07_44.log (The system cannot find the path specified)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:212)
at java.io.FileOutputStream.<init>(FileOutputStream.java:165)
at untargz.Untargz.untar(Untargz.java:37)
at untargz.Untargz.run(Untargz.java:55)
at untargz.Untargz.main(Untargz.java:64)
Is there a way I am supposed to place My directories so that the extraction Happens or what exactly is My Mistake?
If the tar file contains an entry for a file foo/bar.txt but doesn't contain a previous directory entry for foo/ then your code will be trying to create a file in a directory that doesn't exist. Try adding
destFile.getParentFile().mkdirs();
just before you create the FileOutputStream.
Alternatively, if you don't mind your code depending on Ant as a library then you can delegate the whole unpacking process to an Ant task rather than doing it by hand. Something like this (not fully tested):
Project p = new Project();
Untar ut = new Untar();
ut.setProject(p);
ut.setSrc(tarFile);
if(tarFile.getName().endsWith(".gz")) {
ut.setCompression((UntarCompressionMethod)EnumeratedAttribute.getInstance(UntarCompressionMethod.class, "gzip"));
}
ut.setDest(destDir);
ut.perform();