Вот универсальная функция для преобразования либо объекта timedelta
, либо обычного номера (в виде секунд или минут и т. д.) в красиво отформатированную строку. Я взял фантастический ответ mpounsett по дублированному вопросу, сделал его немного более гибким, улучшенным читабельностью и добавленной документацией.
Вы найдете, что это самый гибкий ответ здесь, поскольку он позволяет вам:
Функция:
from string import Formatter
from datetime import timedelta
def strfdelta(tdelta, fmt='{D:02}d {H:02}h {M:02}m {S:02}s', inputtype='timedelta'):
"""Convert a datetime.timedelta object or a regular number to a custom-
formatted string, just like the stftime() method does for datetime.datetime
objects.
The fmt argument allows custom formatting to be specified. Fields can
include seconds, minutes, hours, days, and weeks. Each field is optional.
Some examples:
'{D:02}d {H:02}h {M:02}m {S:02}s' --> '05d 08h 04m 02s' (default)
'{W}w {D}d {H}:{M:02}:{S:02}' --> '4w 5d 8:04:02'
'{D:2}d {H:2}:{M:02}:{S:02}' --> ' 5d 8:04:02'
'{H}h {S}s' --> '72h 800s'
The inputtype argument allows tdelta to be a regular number instead of the
default, which is a datetime.timedelta object. Valid inputtype strings:
's', 'seconds',
'm', 'minutes',
'h', 'hours',
'd', 'days',
'w', 'weeks'
"""
# Convert tdelta to integer seconds.
if inputtype == 'timedelta':
remainder = int(tdelta.total_seconds())
elif inputtype in ['s', 'seconds']:
remainder = int(tdelta)
elif inputtype in ['m', 'minutes']:
remainder = int(tdelta)*60
elif inputtype in ['h', 'hours']:
remainder = int(tdelta)*3600
elif inputtype in ['d', 'days']:
remainder = int(tdelta)*86400
elif inputtype in ['w', 'weeks']:
remainder = int(tdelta)*604800
f = Formatter()
desired_fields = [field_tuple[1] for field_tuple in f.parse(fmt)]
possible_fields = ('W', 'D', 'H', 'M', 'S')
constants = {'W': 604800, 'D': 86400, 'H': 3600, 'M': 60, 'S': 1}
values = {}
for field in possible_fields:
if field in desired_fields and field in constants:
values[field], remainder = divmod(remainder, constants[field])
return f.format(fmt, **values)
Демоверсия:
>>> td = timedelta(days=2, hours=3, minutes=5, seconds=8, microseconds=340)
>>> print strfdelta(td)
02d 03h 05m 08s
>>> print strfdelta(td, '{D}d {H}:{M:02}:{S:02}')
2d 3:05:08
>>> print strfdelta(td, '{D:2}d {H:2}:{M:02}:{S:02}')
2d 3:05:08
>>> print strfdelta(td, '{H}h {S}s')
51h 308s
>>> print strfdelta(12304, inputtype='s')
00d 03h 25m 04s
>>> print strfdelta(620, '{H}:{M:02}', 'm')
10:20
>>> print strfdelta(49, '{D}d {H}h', 'h')
2d 1h
Вместо того, чтобы пытаться адресовать ресурс в качестве файла , просто попросите ClassLoader вернуть InputStream для ресурса вместо getResourceAsStream :
InputStream in = getClass().getResourceAsStream("/file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
Пока ресурс file.txt
доступен в пути к классам, этот подход будет работать одинаково независимо от того, находится ли ресурс file.txt
в файле classes/
] или внутри jar
.
URI is not hierarchical
происходит потому, что URI для ресурса в файле jar будет выглядеть примерно так: file:/example.jar!/file.txt
. Вы не можете прочитать записи в файле jar
(файл zip
), как будто это был обычный старый файл .
Это объясняется ответами на:
После многократного поиска в Java единственное решение, которое, похоже, работает для меня, - это вручную прочитать файл jar, если вы не находитесь в среде разработки (IDE):
/** @return The root folder or jar file that the class loader loaded from */
public static final File getClasspathFile() {
return new File(YourMainClass.class.getProtectionDomain().getCodeSource().getLocation().getFile());
}
/** @param resource The path to the resource
* @return An InputStream containing the resource's contents, or
* <b><code>null</code></b> if the resource does not exist */
public static final InputStream getResourceAsStream(String resource) {
resource = resource.startsWith("/") ? resource : "/" + resource;
if(getClasspathFile().isDirectory()) {//Development environment:
return YourMainClass.class.getResourceAsStream(resource);
}
final String res = resource;//Jar or exe:
return AccessController.doPrivileged(new PrivilegedAction<InputStream>() {
@SuppressWarnings("resource")
@Override
public InputStream run() {
try {
final JarFile jar = new JarFile(getClasspathFile());
String resource = res.startsWith("/") ? res.substring(1) : res;
if(resource.endsWith("/")) {//Directory; list direct contents:(Mimics normal getResourceAsStream("someFolder/") behaviour)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Enumeration<JarEntry> entries = jar.entries();
while(entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if(entry.getName().startsWith(resource) && entry.getName().length() > resource.length()) {
String name = entry.getName().substring(resource.length());
if(name.contains("/") ? (name.endsWith("/") && (name.indexOf("/") == name.lastIndexOf("/"))) : true) {//If it's a folder, we don't want the children's folders, only the parent folder's children!
name = name.endsWith("/") ? name.substring(0, name.length() - 1) : name;
baos.write(name.getBytes(StandardCharsets.UTF_8));
baos.write('\r');
baos.write('\n');
}
}
}
jar.close();
return new ByteArrayInputStream(baos.toByteArray());
}
JarEntry entry = jar.getJarEntry(resource);
InputStream in = entry != null ? jar.getInputStream(entry) : null;
if(in == null) {
jar.close();
return in;
}
final InputStream stream = in;//Don't manage 'jar' with try-with-resources or close jar until the
return new InputStream() {//returned stream is closed(closing the jar closes all associated InputStreams):
@Override
public int read() throws IOException {
return stream.read();
}
@Override
public int read(byte b[]) throws IOException {
return stream.read(b);
}
@Override
public int read(byte b[], int off, int len) throws IOException {
return stream.read(b, off, len);
}
@Override
public long skip(long n) throws IOException {
return stream.skip(n);
}
@Override
public int available() throws IOException {
return stream.available();
}
@Override
public void close() throws IOException {
try {
jar.close();
} catch(IOException ignored) {
}
stream.close();
}
@Override
public synchronized void mark(int readlimit) {
stream.mark(readlimit);
}
@Override
public synchronized void reset() throws IOException {
stream.reset();
}
@Override
public boolean markSupported() {
return stream.markSupported();
}
};
} catch(Throwable e) {
e.printStackTrace();
return null;
}
}
});
}
Примечание: приведенный выше код, похоже, работает правильно для файлов jar, если он находится в основном классе. Я не уверен, почему.
Вы также можете просто использовать java.nio. Вот пример того, как slurp в тексте из файла в resourcePath
в пути к классам:
new String(Files.readAllBytes(Paths.get(getClass().getResource(resourcePath).toURI())))
inputstream
.
– George Curington
5 May 2016 в 00:44
Чтобы получить доступ к файлу в банке, у вас есть две возможности:
getClass().getResourceAsStream("file.txt")
Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt")
Первый вариант может не работать, если jar используется в качестве плагина.
У меня была эта проблема раньше, и я сделал резервный способ загрузки. В основном первый способ работы внутри .jar-файла и второго способа работает внутри eclipse или другой среды IDE.
public class MyClass {
public static InputStream accessFile() {
String resource = "my-file-located-in-resources.txt";
// this is the path within the jar file
InputStream input = MyClass.class.getResourceAsStream("/resources/" + resource);
if (input == null) {
// this is how we load file within editor (eg eclipse)
input = MyClass.class.getClassLoader().getResourceAsStream(resource);
}
return input;
}
}
До сих пор (декабрь 2017 г.) это единственное найденное решение, которое работает как внутри, так и снаружи IDE.
Использовать PathMatchingResourcePatternResolver
Примечание: он работает также в spring-boot
. В этом примере я читаю некоторые файлы, расположенные в src / main / resources / my_folder:
try {
// Get all the files under this inner resource folder: my_folder
String scannedPackage = "my_folder/*";
PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
Resource[] resources = scanner.getResources(scannedPackage);
if (resources == null || resources.length == 0)
log.warn("Warning: could not find any resources in this scanned package: " + scannedPackage);
else {
for (Resource resource : resources) {
log.info(resource.getFilename());
// Read the file content (I used BufferedReader, but there are other solutions for that):
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
// ...
// ...
}
bufferedReader.close();
}
}
} catch (Exception e) {
throw new Exception("Failed to read the resources folder: " + e.getMessage(), e);
}
Если вы хотите читать как файл, я считаю, что все еще есть аналогичное решение:
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("file/test.xml").getFile());
file:
URL-адресом.
– VGR
5 March 2016 в 19:07
Убедитесь, что вы работаете с правильным разделителем. Я заменил все /
на относительный путь с помощью File.separator
. Это отлично работало в среде IDE, однако не работало в JAR сборки.
Если вы используете Spring, вы можете использовать следующий метод для чтения файла из src / main / resources:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.springframework.core.io.ClassPathResource;
public String readFile() {
StringBuilder result = new StringBuilder("");
ClassPathResource resource = new ClassPathResource("filename.txt");
try (InputStream inputStream = resource.getInputStream()) {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = bufferedReader.readLine()) != null) {
result.append(line);
}
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return result.toString();
}
InputStream
(например,File.exists()
), поэтому моя игра может определить, использовать ли файл по умолчанию или нет. Благодарю. – PrinceCJC 5 December 2013 в 17:23getClass().getResource("**/folder**/file.txt")
заставила его работать, потому что у меня была эта папка в том же каталоге, что и моя банка :). – PrinceCJC 5 December 2013 в 17:33getResourceAsStream
возвращает значение null, если ресурс не существует, так что может быть вашим & quot; существует & quot; контрольная работа. – Drew MacInnis 5 December 2013 в 21:05