Есть ли в groovy простой способ получить имя файла без расширения?

Скажем, у меня есть что-то вроде этого:

new File("test").eachFile() { file->  
println file.getName()  
}

Это печатает полное имя файла каждого файла в каталоге test. Есть ли способ Groovy получить имя файла без расширения? (Или я вернулся в страну регулярных выражений?)


person Electrons_Ahoy    schedule 14.10.2009    source источник
comment
Иногда файлы не имеют расширения, но имеют в них ..   -  person Bart Kiers    schedule 15.10.2009


Ответы (10)


Я считаю, что самым крутым способом было бы:

file.name.lastIndexOf('.').with {it != -1 ? file.name[0..<it] : file.name}

или с помощью простого регулярного выражения:

file.name.replaceFirst(~/\.[^\.]+$/, '')

также для таких целей есть java-библиотека apache commons-io, на которую вы можете легко положиться, если используете maven:

org.apache.commons.io.FilenameUtils.getBaseName(file.name)
person Nikita Volkov    schedule 30.06.2011

Самый чистый способ.

String fileWithoutExt = file.name.take(file.name.lastIndexOf('.'))

person Pier    schedule 19.05.2016
comment
он дает не интуитивно ожидаемые результаты в следующих случаях: assert ['.foobar', 'foobar'].collect { it.take(it.lastIndexOf('.')) } == ['', ''] - person maoizm; 02.01.2021

Самый простой способ:

'file.name.with.dots.tgz' - ~/\.\w+$/​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

Результат:

file.name.with.dots
person librucha    schedule 17.02.2017

new File("test").eachFile() { file->  
    println file.getName().split("\\.")[0]
}

Это хорошо работает для таких имен файлов, как: foo, foo.bar

Но если у вас есть файл foo.bar.jar, то приведенный выше код распечатает: foo Если вы хотите, чтобы вместо этого распечатывался foo.bar, то для этого используется следующий код.

new File("test").eachFile() { file->  
    def names = (file.name.split("\\.")
    def name = names.size() > 1 ? (names - names[-1]).join('.') : names[0]
    println name
}
person Mauro Zallocco    schedule 04.10.2012

Класс FilenameUtils, который является частью пакета io для Apache Commons, имеет надежное решение. Пример использования:

import org.apache.commons.io.FilenameUtils

String filename = '/tmp/hello-world.txt'
def fileWithoutExt = FilenameUtils.removeExtension(filename)

Это не лучший способ, но может быть полезен, если вам нужно поддерживать множество крайних случаев.

person Jay P.    schedule 26.12.2015
comment
Apache Commons каждый раз! группа компиляции: «commons-io», имя: «commons-io», версия: «2.6» на момент написания... - person mike rodent; 07.11.2018

Возможно, не так просто, как вы ожидали, но работает:

new File("test").eachFile { 
  println it.name.lastIndexOf('.') >= 0 ? 
     it.name[0 .. it.name.lastIndexOf('.')-1] : 
     it.name 
  }
person Alexander Egger    schedule 15.10.2009

Как упоминалось в комментариях, где заканчивается имя файла и начинается расширение, зависит от ситуации. В моей ситуации мне нужно было получить базовое имя (файл без пути, и без расширения) следующих типов файлов: { foo.zip, bar/foo.tgz, foo.tar.gz } => все необходимо создать «foo» в качестве имени файла без расширения. (Большинство решений с учетом foo.tar.gz дадут foo.tar.)

Вот одно (очевидное) решение, которое даст вам все до первого "."; при желании вы можете получить все расширение либо по частям, либо (в данном случае) в виде единого остатка (разделив имя файла на 2 частей). (Примечание: хотя это и не связано с текущей задачей, я также удаляю путь, вызывая file.name.)

file=new File("temp/foo.tar.gz")
file.name.split("\\.", 2)[0]    // => return "foo" at [0], and "tar.gz" at [1]
person michael    schedule 16.04.2014
comment
Я не знаю, почему я не видел ответа Мауро, пока не опубликовал это. Это должен был быть комментарий, так как он почти идентичен, но без forEach/closure. Я оставлю это на данный момент, так как его проще читать, если вы не знакомы с синтаксисом { file -> yada yada } (который, конечно, был в исходном вопросе, но в остальном не имеет отношения к проблеме). - person michael; 16.04.2014

Вы можете лучше использовать регулярные выражения. Функция, подобная следующей, сделает свое дело:

def getExtensionFromFilename(filename) {
  def returned_value = ""
  m = (filename =~ /(\.[^\.]*)$/)
  if (m.size()>0) returned_value = ((m[0][0].size()>0) ? m[0][0].substring(1).trim().toLowerCase() : "");
  return returned_value
}
person Alex    schedule 12.06.2010

Примечание

import java.io.File;

def fileNames    = [ "/a/b.c/first.txt", 
                     "/b/c/second",
                     "c:\\a\\b.c\\third...",
                     "c:\\a\b\\c\\.text"
                   ]

def fileSeparator = "";

fileNames.each { 
    // You can keep the below code outside of this loop. Since my example
    // contains both windows and unix file structure, I am doing this inside the loop.
    fileSeparator= "\\" + File.separator;
    if (!it.contains(File.separator)) {
        fileSeparator    =  "\\/"
    }

    println "File extension is : ${it.find(/((?<=\.)[^\.${fileSeparator}]+)$/)}"
    it    =  it.replaceAll(/(\.([^\.${fileSeparator}]+)?)$/,"")

    println "Filename is ${it}" 
}

Некоторые из приведенных ниже решений (кроме того, что использует библиотеку apache) не работают для этого примера — c:/test.me/firstfile

Если я попытаюсь найти расширение для вышеуказанной записи, я получу ".me/firstfile" - :(

Лучшим подходом будет найти последнее вхождение File.separator, если оно присутствует, а затем найти имя файла или расширение.

Примечание: (Ниже показан небольшой трюк. В Windows разделителем файлов является \. Но это специальный символ в регулярном выражении, поэтому, когда мы используем переменную, содержащую File.separator в регулярное выражение, я должен избежать его, поэтому я делаю это:

def fileSeparator= "\\" + File.separator;

Надеюсь, это имеет смысл :)

Попробуйте это:

import java.io.File;

String strFilename     =  "C:\\first.1\\second.txt";
// Few other flavors 
// strFilename = "/dd/dddd/2.dd/dio/dkljlds.dd"

def fileSeparator= "\\" + File.separator;
if (!strFilename.contains(File.separator)) {
    fileSeparator    =  "\\/"
}

def fileExtension = "";
(strFilename    =~ /((?<=\.)[^\.${fileSeparator}]+)$/).each { match,  extension -> fileExtension = extension }
println "Extension is:$fileExtension"
person Sajumon Joseph    schedule 19.02.2016

person    schedule
comment
Я тоже :) Я, видимо, привел пример, как получить имя файла без пути, но С расширением. Так я и не ответил на вопрос автора. - person Marco; 13.04.2017