Refactoring else-if operators with different extensions? [duplicate] - java

This question already has answers here:
Modifying if-else to strategy pattern
(2 answers)
Closed 9 years ago.
I want to know how we better way refctoring this part of code with else-if operators. When is performed eguals check with different extentions?
Code:
private void findFiles(String path) {
try {
File root = new File(path);
File[] list = root.listFiles();
for (File currentFile : list) {
if (currentFile.isDirectory()) {
findFiles(currentFile.getAbsolutePath());
} else {
if (currentFile.getName().toLowerCase().endsWith((".txt"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".pdf"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".doc"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".docx"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".html"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".htm"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".xml"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".djvu"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".djv"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".rar"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".rtf"))) {
queue.put(currentFile);
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Questions:
How better way to refactoring code? Make it simpler for
understanding.
Can we use some another way to check extentions
variants?
Thanks,
Nazar.

You can replace your whole list of checking extensions with this:
// outside the loop (or even method):
Set<String> extensions = new HashSet<>(Arrays.asList(".txt", ".pdf", ".doc",
".docx", ".html", ".htm", ".xml", ".djvu", ".rar", ".rtf"));
// in the loop:
String fileName = currentFile.getName().toLowerCase();
if (extensions.contains(fileName.substring(fileName.lastIndexOf(".")))) {
queue.put(currentFile);
}

You could use a regex:
String s = currentFile.getName().toLowerCase();
if (s.matches("^.+?\\.(txt|pdf|doc|docx|html|htm|xml|djvu|rar|rtf)$")) {
queue.put(currentFile);
}
That assumes that the action to be taken is the same for all extensions.
In details:
^ beginning of string
.+ one or more characters
? non greedy -> don't consume characters that match the rest of the regex
\\. a period
(pdf|doc) match pdf or doc
$ the end of the string

The best solution would be to refactor this to the STRATEGY Pattern, as seen here:

I would create a getExtension() method, which returns the extension of the file, and a final set of accepted extensions:
private static final Set<String> ACCEPTED_EXTENSIONS =
Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(".txt", ".doc", ...));
private String getExtension(File f) {
// TODO return the extension of the file
}
The code would then be redueced to:
private void findFiles(String path) {
try {
File root = new File(path);
File[] list = root.listFiles();
for (File currentFile : list) {
if (currentFile.isDirectory()) {
findFiles(currentFile.getAbsolutePath());
}
else if (ACCEPTED_EXTENSIONS.contains(getExtension(currentFile))) {
queue.put(currentFile);
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
Or even better, I would create a FileFilter which only accepts directories and files with one of the accepted extensions (using the same set and getExtension() method), and would use root.listFiles(fileFilter).

Create a method
public boolean isPermissibleFileType(String fileName){
String[] fileTypes = {".pdf",".doc",".docx",".html",".htm",".xml",".djvu",".djv",".rar",".rtf"};
return Arrays.asList(fileTypes).contains(fileName.substring(fileName.lastIndexOf('.')).toLowerCase());
}
Use Method in Loop
private void findFiles(String path) {
try {
File root = new File(path);
File[] list = root.listFiles();
for (File currentFile : list) {
if (currentFile.isDirectory()) {
findFiles(currentFile.getAbsolutePath());
} else {
if(isPermissibleFileType(currentFile.getName()){
queue.put(currentFile);
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

You can extract the extension checks into some helper method using class FileNameFilter. And then for recursion you can use your original finder method.

Related

Replacing Future<Integer> with Future<Void>

I am writing an application that searches for Java files in a given directory and its subdirectories and writes all the strings from those files in reverse order to a new folder. Each directory and file is handled in a separate thread.
At the moment my program works correctly, but I want to change its behavior.
Right now, the program overwrites the files correctly and outputs the number of overwritten files to the console at the end. I want my program to just overwrite the files and display the line "All files overwritten" at the end. But I don't quite understand how I can change my code and replace Future (I think that's my problem). Here is part of the code from the Main class:
ExecutorService pool = Executors.newCachedThreadPool();
ReverseWritter reverseWritter = new ReverseWritter(dirToSearch, dirToStorePath + "//" + dirToStoreName, pool);
Future<Integer> res = pool.submit(reverseWritter);
try {
System.out.println(res.get() + " files reversed");
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
pool.shutdown();
Here's the method that overwrites the file:
public boolean reverseWrite(File file) {
if (file.isFile() && file.toString().endsWith(".java")) {
String whereTo = dirToStorePathName + "\\" + file.getName().substring(0, file.getName().indexOf(".java")) + "Reversed" + ".java";
try ( Scanner myReader = new Scanner(file); FileWriter myWriter = new FileWriter(whereTo);) {
while (myReader.hasNextLine()) {
String data = myReader.nextLine();
myWriter.write(new StringBuffer(data).reverse().toString());
myWriter.write(System.getProperty("line.separator"));
}
} catch (FileNotFoundException e) {
System.out.println("An error occurred.");
e.printStackTrace();
return false;
} catch (IOException e) {
System.out.println("An error occurred.");
e.printStackTrace();
return false;
}
}
return true;
}
And this is the call method (my class implements the Callable interface):
#Override
public Integer call() {
int count = 0;
try {
File[] files = dirToSearch.listFiles();
ArrayList<Future<Integer>> result = new ArrayList<>();
for (File f : files) {
if (f.isDirectory()) {
ReverseWritter reverseWritter = new ReverseWritter(f, dirToStorePathName, pool);
Future<Integer> rez = pool.submit(reverseWritter);
result.add(rez);
} else if (reverseWrite(f)) {
count++;
}
for (Future<Integer> rez : result) {
count += rez.get();
}
}
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
return count;
}
You just need to change the class to implement Callable<Void> and remove the operations which do the counting. Change the return type of call from Integer to Void.
public class ReverseWriterCallable implements Callable<Void> {
#Override
public Void call() throws Exception {
//do stuff
//don't do the counting operations
//when return type is Void you can only return null
return null;
}
}
Or implement Runnable and submit it to the executor service.
public class ReverseWriterRunnable implements Runnable {
#Override
public void run() {
//do stuff
//don't do the counting operations
}
}
Then just don't care about the result of the Future:
try {
res.get();
System.out.println("All files reversed");
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
pool.shutdown();

Search for string in all files inside a Directory

I want to search for particular string inside all files in a Directory.
Ex: Search for "tiger" in path D:/test/chapters/
D:/test/chapters
/chapter1.log
/chapter2.log
/chapter3.log all these sub files under D:/test/chapters/ .
Sample code I have tried :
public class Example {
public Example() {
super();
}
public int plugin_execute() {
boolean foundstring=false;
try {
File dir = new File("D:/test/chapters");
String[] children = dir.list();
if (children == null) {
System.out.println("does not exist is not a directory");
} else {
for (int i = 0; i < children.length; i++) {
String filename = children[i];
System.out.println(filename);
if (filename !=null) {
foundstring = testString(filename, "tiger");
System.out.println("failed");
}
//Search for entry in file
if (!foundstring) {
return //failuremsg
} else {
System.out.println("failed");
return //succes
}
}
}
return 1;
} catch (Exception e) {
return //error mssg
}
}
private boolean teststring(String filePath, String str) {
BufferedReader br = null;
File file = new File(filePath);
boolean result = false;
if(!file.exists())
return false;
try {
br = new BufferedReader(new FileReader(filePath));
String sCurrentLine;
while ((sCurrentLine = br.readLine()) != null) {
if (sCurrentLine.contains(str)) {
result = true;
System.out.println(str);
System.out.println("Found entry ");
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null)br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
}
It only returns the output of last file, means if it search success in last file it return success otherwise failed.
But I want success if string is found in first file. i.e chapter1 should return success, if not found in Chapter1 it should continue search in chapter2 ....
Please suggest how can I modify this code..
Problem: Simple mix-up with ! and true/false locations.
Solution: Change this
if (! foundString)
{
return // failuremsg
}
else
{
System.out.println("failed");
return // success
}
to
if (foundString)
{
// return success message
}
else
{
// return failure message
}
Another problem I believe I see in your code is that the line foundstring = findString(filename, "tiger"); calls the method findString, whereas the other method you posted in your code is testString. I assume this is a name mix up.
public void listFiles(Path dir , String text)
{
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(dir))
{
for (Path path : directoryStream)
{
if (Files.isRegularFile(path) && Files.isReadable(path))
{
//this.findString(path, text);
}
}
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
private boolean findString(Path file, String text)
{
//Your implementation
return true;
}

Is it possible to know whether the copied content in clipboard is mp3 file using awt.Toolkit and Clipboard in java

I am trying to write a code which runs at background and monitors the copy actions for copying a .mp3 file or a folder containing a .mp3 file
{
Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
if (cb.isDataFlavorAvailable(DataFlavor.javaFileListFlavor))
{
try {
String name = ""+cb.getData(DataFlavor.javaFileListFlavor);
boolean found = false;
if (name.toLowerCase().endsWith(".mp3]"))
{
System.out.println("Is MP3");
found = true;
}
if (!found)
{
System.out.println("Is not MP3");
}
}
catch(UnsupportedFlavorException ex)
{
ex.printStackTrace();
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
}
Basically, yes. You need to check the Clipboard contents to see if it supports the DataFlavor.javaFileListFlavor DataFlavor. If it does, you need to iterate over the contents (which is java.util.List of Files) and make a determination of the content.
The following only checks to see if the files are .mp3 files (by checking the name extension), but it wouldn't be hard to check for isDirectory and do a recursive check of the directory...
Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
if (cb.isDataFlavorAvailable(DataFlavor.javaFileListFlavor)) {
try {
List files = (List) cb.getData(DataFlavor.javaFileListFlavor);
boolean found = false;
for (Object o : files) {
if (o instanceof File) {
File f = (File) o;
if (f.getName().toLowerCase().endsWith(".mp3")) {
System.out.println("I haz MP3");
found = true;
}
}
}
if (!found) {
System.out.println("I notz haz MP3");
}
} catch (UnsupportedFlavorException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}
My suggestion is:
http://msdn.microsoft.com/en-us/library/ff468802(v=vs.85).aspx
Using native windows C function and user JNA(Java native access library) to complete your requirement.
JNA:
https://github.com/twall/jna

Programmatically retrieve permissions from manifest.xml in android

I have to programmatically retrieve permissions from the manifest.xml of an android application and I don't know how to do it.
I read the post here but I am not entirely satisfied by the answers.
I guess there should be a class in the android API which would allow to retrieve information from the manifest.
Thank you.
You can get an application's requested permissions (they may not be granted) using PackageManager:
PackageInfo info = getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
String[] permissions = info.requestedPermissions;//This array contains the requested permissions.
I have used this in a utility method to check if the expected permission is declared:
//for example, permission can be "android.permission.WRITE_EXTERNAL_STORAGE"
public boolean hasPermission(String permission)
{
try {
PackageInfo info = getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
if (info.requestedPermissions != null) {
for (String p : info.requestedPermissions) {
if (p.equals(permission)) {
return true;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
Here's a useful utility method that does just that (in both Java & Kotlin).
Java
public static String[] retrievePermissions(Context context) {
final var pkgName = context.getPackageName();
try {
return context
.getPackageManager()
.getPackageInfo(pkgName, PackageManager.GET_PERMISSIONS)
.requestedPermissions;
} catch (PackageManager.NameNotFoundException e) {
return new String[0];
// Better to throw a custom exception since this should never happen unless the API has changed somehow.
}
}
Kotlin
fun retrievePermissions(context: Context): Array<String> {
val pkgName = context.getPackageName()
try {
return context
.packageManager
.getPackageInfo(pkgName, PackageManager.GET_PERMISSIONS)
.requestedPermissions
} catch (e: PackageManager.NameNotFoundException) {
return emptyArray<String>()
// Better to throw a custom exception since this should never happen unless the API has changed somehow.
}
}
You can get a working class from this gist.
Use this:
public static String getListOfPermissions(final Context context)
{
String _permissions = "";
try
{
final AssetManager _am = context.createPackageContext(context.getPackageName(), 0).getAssets();
final XmlResourceParser _xmlParser = _am.openXmlResourceParser(0, "AndroidManifest.xml");
int _eventType = _xmlParser.getEventType();
while (_eventType != XmlPullParser.END_DOCUMENT)
{
if ((_eventType == XmlPullParser.START_TAG) && "uses-permission".equals(_xmlParser.getName()))
{
for (byte i = 0; i < _xmlParser.getAttributeCount(); i ++)
{
if (_xmlParser.getAttributeName(i).equals("name"))
{
_permissions += _xmlParser.getAttributeValue(i) + "\n";
}
}
}
_eventType = _xmlParser.nextToken();
}
_xmlParser.close(); // Pervents memory leak.
}
catch (final XmlPullParserException exception)
{
exception.printStackTrace();
}
catch (final PackageManager.NameNotFoundException exception)
{
exception.printStackTrace();
}
catch (final IOException exception)
{
exception.printStackTrace();
}
return _permissions;
}
// Test: Log.wtf("test", getListOfPermissions(getApplicationContext()));
If anyone is looking for a short Kotlin Version
fun Manifest.getDeclaredPermissions(context: Context): Array<String> {
return context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS).requestedPermissions
}
I have a simple C# code, "using System.Xml"
private void ShowPermissions()
{
XmlDocument doc = new XmlDocument();
doc.Load("c:\\manifest.xml");
XmlNodeList nodeList = doc.GetElementsByTagName("uses-permission");
foreach(XmlNode node in nodeList)
{
XmlAttributeCollection Attr = node.Attributes;
string Permission=Attr["android:permission"].Value;
MessageBox.Show(Permission);
}
}

Java continue executing loop if exception was throwd

Example: say I want to open a file. If I get a FileNotFoundException, I need to wait for some time and try again. How can I gracefully do that? Or do I need to use nested try/catch blocks?
Example :
public void openFile() {
File file = null;
try {
file = new <....>
} catch(FileNotFoundException e) {
}
return file;
}
You could use a do { ... } while (file == null) construct.
File file = null;
do {
try {
file = new <....>
} catch(FileNotFoundException e) {
// Wait for some time.
}
} while (file == null);
return file;
public File openFile() {
File file = null;
while (file == null) {
try {
file = new <....>
} catch(FileNotFoundException e) {
// Thread.sleep(waitingTime) or what you want to do
}
}
return file;
}
Note that this is a somewhat dangerous method, since there is no way to break out unless the file eventually appears. You could add a counter and give up after a certain number of tries, eg:
while (file == null) {
...
if (tries++ > MAX_TRIES) {
break;
}
}
public File openFile() {
File file = null;
while(true){
try {
file = new <....>
} catch(FileNotFoundException e) {
//wait for sometime
}
if(file!=null){
break;
}
}
return file;
}

Categories

Resources