Java: как получить части пути - PullRequest
5 голосов
/ 08 июня 2011

Это должно быть довольно просто, но я просто застрял. Скажем, у вас есть путь /a/b/c/. Я хотел бы преобразовать это в массив, содержащий:

  • /
  • /a/
  • /a/b/
  • /a/b/c/

Косая черта в начале и конце должна быть необязательной. Кто-нибудь хочет помочь?

Я собираюсь использовать его для функции, которая создает каталог, и я хочу, чтобы он также создавал все недостающие части и не вызывал ошибку, если, например, a или b не существует.


Обновление: Я бы, конечно, использовал File.mkdirs(), если бы мог, но это не в локальной файловой системе. Это упрощает взаимодействие с библиотекой SFTP, в которой есть только метод mkdir, принимающий путь в виде строки.

Ответы [ 6 ]

11 голосов
/ 08 июня 2011

Почему бы просто не использовать File.mkdirs()?


edit: согласно вашему требованию не использовать File.mkdirs ():

Я все еще думаю, что этопроще использовать File в качестве вспомогательного класса:

package com.example.test;

import java.io.File;
import java.util.LinkedList;
import java.util.List;

public class FileSplitter {
    final private File path;

    public List<String> getPathStrings()
    {
        LinkedList<String> list = new LinkedList<String>();
        File p = this.path;
        while (p != null)
        {
            list.addFirst(p.getPath());
            p = p.getParentFile();
        }
        return list;
    }

    public FileSplitter(File path) { this.path = path; }

    public static void main(String[] args) {
        doit(new File("/foo/bar/baz"));
        doit(new File("/bam/biff/boom/pow"));
    }

    private static void doit(File file) {
        for (String s : new FileSplitter(file)
                .getPathStrings())
            System.out.println(s);      
    }
}

На моей машине (Windows) это распечатывает:

\
\foo
\foo\bar
\foo\bar\baz
\
\bam
\bam\biff
\bam\biff\boom
\bam\biff\boom\pow

Если вам нужно использовать косые черты независимо от того,что, тогда я бы либо реализовал использование строк вместо файлов, либо просто сделал бы .replace('\\','/') в точке использования.


Наконец, вот подход, который может быть более полезным для вашего конечного приложения.

Он имеет тот же вывод, что и предыдущий, но поддается инверсии управления, где вы можете выполнить свой пользовательский mkdir() как псевдо-Runnable для передачи в качестве шага итератору пути:

package com.example.test;

import java.io.File;

public class PathRunner
{
    final private File path;
    public PathRunner(File path) { 
        this.path = path; 
    }

    public interface Step
    {
        public boolean step(File path);
    }

    public boolean run(Step step) 
    {
        return run(step, this.path);
    }
    private boolean run(Step step, File p)
    {
        if (p == null)
            return true;
        else if (!run(step, p.getParentFile()))
            return false;
        else
            return step.step(p);
    }

    /**** test methods ****/

    public static void main(String[] args) {
        doit(new File("/foo/bar/baz"));
        doit(new File("/bam/biff/boom/pow"));
    }
    private static boolean doit(File path) {
        Step step = new Step()
        {
            @Override public boolean step(File path) {
                System.out.println(path);
                return true;
                /* in a mkdir operation, here's where you would call: 

                return yourObject.mkdir(
                    path.getPath().replace('\\', '/')
                );
                 */
            }               
        };
        return new PathRunner(path).run(step);
    }
}
5 голосов
/ 08 июня 2011

Если вам нужно что-то примитивное. Попробуйте разделить и добавить.

public class StackOverflow {

    public static void main(String args[]) {

        String[] folders = "/a/b/c/".split("/");
        String[] paths = new String[folders.length];
        String path = "";

        for (int i = 0; i < folders.length; i++) {
            path +=   folders[i] + "/";
            paths[i] = path;
        }
    }
}

Это вывод блока кода:

run:
/
/a/
/a/b/
/a/b/c/
BUILD SUCCESSFUL (total time: 0 seconds)
4 голосов
/ 08 июня 2011

Класс File поддерживает это.

public static void main(String... args) {
    split(new File("/a/b/c/d/e"));
    split(new File("\\A\\B\\C\\D\\E"));
}

private static void split(File file) {
    File parent = file.getParentFile();
    if (parent != null) split(parent);
    System.out.println(file);
}

на отпечатках окон

\
\a
\a\b
\a\b\c
\a\b\c\d
\a\b\c\d\e
\
\A
\A\B
\A\B\C
\A\B\C\D
\A\B\C\D\E
2 голосов
/ 12 сентября 2012

Заканчивается этим кодом:

   public String[] componizePath(String path)
   {
      ArrayList<String> parts = new ArrayList<String>();  

      int index = 0;
      while(index < path.length())
      {
         if(path.charAt(index) == '/' || index == path.length()-1)
         {
            parts.add(path.substring(0, index+1));
         }
         index++;
      }

      return parts.toArray(new String[0]);
   }

JUnit тесты:

   @Test
   public void componizePath_EmptyPath()
   {
      String[] actual = getSftp().componizePath("");
      String[] expected = new String[0];
      assertArrayEquals(expected, actual);
   }

   @Test
   public void componizePath_RootPath()
   {
      String[] actual = getSftp().componizePath("/");
      String[] expected = new String[] {"/"};
      assertArrayEquals(expected, actual);
   }

   @Test
   public void componizePath_SimplePath()
   {
      String[] actual = getSftp().componizePath("a");
      String[] expected = new String[] {"a"};
      assertArrayEquals(expected, actual);
   }

   @Test
   public void componizePath_SimplePathWithTrailingSlash()
   {
      String[] actual = getSftp().componizePath("a/");
      String[] expected = new String[] {"a/"};
      assertArrayEquals(expected, actual);
   }

   @Test
   public void componizePath_ComplexerPath()
   {
      String[] actual = getSftp().componizePath("a/b/cc");
      String[] expected = new String[] {"a/", "a/b/", "a/b/cc"};
      assertArrayEquals(expected, actual);
   }

   @Test
   public void componizePath_ComplexerPathWithTrailingSlash()
   {
      String[] actual = getSftp().componizePath("a/b/c/");
      String[] expected = new String[] {"a/", "a/b/", "a/b/c/"};
      assertArrayEquals(expected, actual);
   }

   @Test
   public void componizePath_ComplexerPathWithLeadingSlash()
   {
      String[] actual = getSftp().componizePath("/a/b/c");
      String[] expected = new String[] {"/", "/a/", "/a/b/", "/a/b/c"};
      assertArrayEquals(expected, actual);
   }
2 голосов
/ 08 июня 2011

Нет необходимости делать это. File.mkdirs () вместо

0 голосов
/ 08 июня 2011

это должен быть довольно простой алгоритм, если вам задан строковый путь = "/ a / b / c /", вы можете сделать следующее:

def f(st):
    index = 0
    array = []
    while index < len(st):
        if(st[index] == '/'):
            array += [st[:index+1]]

        index += 1
    return array

Это алгоритм Python,Вы можете легко преобразовать это в Java.Конечно, вы можете использовать File.mkdirs (), на который указывали Jason и I82Much, но также интересно посмотреть, как работает алгоритм.

EDIT В случае с Java вы не можетеитерации по строке, но вы можете преобразовать строку в массив списков символов, и когда вы выполняете итерацию, вы пишете условие, что если символ является '/', то создайте новую строку, которая объединяет все символы от первого дотекущий, который мы нашли, который должен быть '/', и добавить его в список строк, который вы инициализировали ранее.Полученный список строк будет тем списком, который вам нужен.Это хорошая практика для вас, если вы попробуете это самостоятельно и посмотрите, как это будет происходить.И, конечно, вы можете перебирать полученный список и создавать каталоги.

...