Golang существует ли файл
Go file tutorial shows how to work with files in Golang. We read files, write to files, create files, list files, and determine their size and modification time.
To work with files in Go, we use the os , ioutil , and fmt packages.
The os.Stat function returns the FileInfo structure describing the file.
6 Answers 6
Edited to add error handling.
It's true that there is no boolean Exists function, but the application code can be simpler if you only want to check for the existence of a file: if _, err := os.Stat("./conf/app.ini"); err == nil < /*exists*/ >else < /*not exists or some other error*/ >
You can use this :
@alex In my personal opinion a function like exists is a bad practice. You should check the various errors types. That's why this function doesn't exist in modern file API.
More of an FYI, since I looked around for a few minutes thinking my question be a quick search away.
How to check if path represents an existing directory in Go?
This was the most popular answer in my search results, but here and elsewhere the solutions only provide existence check. To check if path represents an existing directory, I found I could easily:
Part of my problem was that I expected path/filepath package to contain the isDir() function.
Simple way to check whether file exists or not:
If I told you "Simple way to get rich quick: put money in bank. take money from bank." you would think I was telling you that there were two serial steps required rather than two alternative steps. The problem with this answer is that readers may not understand that you are suggesting two different possible approaches.
I use the following function to check my directories for any errors. It's very similar to previous answers, but I think not nesting if s makes the code more clear. It uses go-homedir to remove ~ from directory paths and pkg/errors to return nicer error messages, but it would be easy to take them out if you don't need their functionality.
Also, to repeat @Dave C's comment, if the reason you're checking a directory's existence is to write a file into it, it's usually better to simply try to open it an deal with errors afterwards:
Go's standard library does not have a function solely intended to check if a file exists or not (like Python's os.path.exists ). What is the idiomatic way to do it?
I don't really get it. At the same minute you say there is no standard function and you write an answer with the standard function. What am I missing ? Shouldn't at least the question be fixed ?
One should better avoid inquiring file existence. B/c of the racy nature of the answer, the obtained information says actually nothing useful above the file existed in the time asked - but it may not exist anymore. The recommendable way is to simply open a file and check if that fails or not.
@zzzz (I know it's been years, this comment is for new readers) I agree in the general case. But my app loads a third party library that takes some file path as initialization data but segfaults if the file does not exist. I think this is a valid scenario for checking if the file exists withou trying to open it to be able to report the error without a fatal crash, as my code doesn't need to read file contents or write to the file directly.
yshadow commented Aug 17, 2017
The condition for checking if the folder / file exist is not exactly correct. os.Stat might fail because of permissions, etc, but the file may still exists. So it should be !os.IsNotExist(err). Using err == nil in that case gives wrong result as the file doesn't exist.
xhesh commented Jul 4, 2017
Go write file
The ioutil.WriteFile function data to the specified file. If the file does not exist, it creates it; otherwise it truncates it before writing.
The example writes a few words into a file.
We have a string from which we create a slice of bytes.
We write the slice of bytes to the given filename with the 0644 permissions.
In the next example, we write a slice of strings to a file.
The WriteString method writes a string to the file.
sunicy commented Jan 2, 2018 •
One more thing, os.IsExist() would be blind to EMPTY FILE. Please always consider IsNotExist() instead.
Here is the official implementation of both of the function.
Go append to file
In order to append to a file, we include the os.O_APPEND flag to the flags of the os.OpenFile function.
The example appends one word to the words.txt file using the WriteString function.
Go delete file
The os.Remove deletes the given file.
The example removes a file.
anonrose commented Aug 18, 2016
Go file size
In the following example, we get the file size.
First, we get the FileInfo structure with os.Stat . Then we get the size of the file in bytes from the structure with Size function.
Go create file
The os.Create function creates or truncates the given file. If the file already exists, it is truncated. If the file does not exist, it is created with mode 0666.
The example creates an empty file.
billzhuang commented Mar 17, 2016
luismanolo commented Jul 28, 2016
lccezinha commented Oct 6, 2016
JitinGuglani commented Apr 23, 2018
Hi all,
very funny behavior of os.stat(). I have written the below code and os.stat() is behaving very wierd.
I am using windows and go lang version : go1.10.1 windows/amd64.
Pls help.
>
// none of these folder exists on my computer so ideally all the returns statements should give error, but only some are giving.
func getName() string //no error if I return the "d:\invalidFolder" value
//return "d:\invalidFolder"
//error if I return the "d:\InvalidFolderName" value
//return "d:\InvalidFolderName"
// error if I return the "d:\xyz\this\folder" value
//return "d:\xyz\this\folder"
// no error if I return the "d:\xyz" value
//return "d:\xyz"
// error, if I return the "d:\doesitgiveError" value
//return "d:\doesitgiveError"
// error if I return "d:\abc" value
return "d:\abc"
>
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Open with Desktop
- View raw
- Copy raw contents Copy raw contents
Copy raw contents
Copy raw contents
В этом разделе мы научим Вас тому, как определять константы, переменные, относящиеся к элементарным типам данных, а также некоторым приемам программирования на Go.
В Go существует множество способов определить переменную.
Основной способ определить переменную в Go - с помощью ключевого слова 'var'. Заметьте, что в Go тип переменной ставится после ее имени:
Определение множества переменных:
Определение переменной с присваиванием ей значения:
Определение множества переменных с присваиванием им значений:
Вам не кажется слишком скучным определять переменные способом, указанным выше? Не волнуйтесь, команда разработчиков Go также посчитала это проблемой. Поэтому если Вы хотите определить переменные с начальными значениями, можно просто опустить указание типа переменных, и код будет выглядеть следующим образом:
Так уже гораздо лучше. Используйте := для замены var и type , это называется коротким объявлением. Но есть одно ограничение: такую форму определения можно использовать только внутри функций. Если Вы попытаетесь использовать ее вне тела функции, Вы получите ошибку компиляции. Поэтому можно использовать var для определения глобальных переменных и короткие объявления в var() .
_ (blank) - это специальное имя переменной. Любое значение, присвоенное такой переменной, будет проигнорировано. Например, мы присваиваем 35 переменной b и пропускаем 34 ( Этот пример просто призван показать, как это работает. Здесь не видно, в чем его польза, но мы будем часто использовать эту возможность Go в работе со значениями, возвращаемыми функциями. ):
Если Вы определили переменную и не использовали ее нигде в своей программе, компилятор покажет Вам ошибку компиляции. Попробуйте скомпилировать следующий код и посмотрите, что будет:
Так называемые константы - это значения, которые были определены во время компиляции, и их нельзя изменить во время работы программы. В Go в качестве типов констант можно использовать число, булев тип и строку.
Константы определяются следующим образом:
в Go для определения переменной булева типа используется bool , значение ее может быть только true или false , и false - это значение по умолчанию. ( Нельзя конвертировать булев тип в числовой и наоборот! )
Целочисленные типы включают в себя как целочисленные типы со знаком, так и без знака. В Go есть и int , и uint , у них одинаковая длина, но в каждом конкретном случае она зависит от операционной системы. В 32-битных системах используются 32-битные типы, в 64-битных - 64-битные. В Go также есть типы, у которых особая длина. К ним относятся rune , int8 , int16 , int32 , int64 , byte , uint8 , uint16 , uint32 , uint64 . Заметьте, что rune - это алиас int32 , а byte - это алиас uint8 .
Есть одна важная вещь, которую надо знать - Вы не можете комбинировать разные типы в одном выражении, такая операция повлечет ошибку компиляции:
Хотя int32 длиннее int8 и является тем же типом, что и int, нельзя использовать их в одним выражении. ( 'c' здесь будет определена как переменная типа int )
К типам с плавающей точкой относятся float32 и float64 ; типа, называемого float , в Go нет. float64 используется по умолчанию при коротком объявлении.
Это все? Нет! Go также поддерживает и комплексные числа. complex128 (с 64-битной вещественной и 64-битной мнимыми частями) является комплексным числом по умолчанию, а если Вам нужны числа поменьше, есть complex64 (с 32-битной вещественной и 32-битной нмимыми частями). Числа представлены в форме RE+IMi , где RE - вещественная часть, а IM - мнимая, последнее i - мнимая единица. Вот пример комплексного числа:
Мы уже говорили о том, что Go использует кодировку UTF-8. Строки представлены двойными кавычками "" или обратными кавычками `` .
Менять отдельные символы в строках по индексу невозможно. Например, при компиляции следующего кода вы получите ошибку:
Что если нам действительно хочется изменить лишь один символ в строке? Попробуем следующее:
Для того, чтобы объединить две строки, используйте оператор + :
Что, если мы захотим определить строковую переменную, значение которой располагается на разных строках?
` все символы в строке воспринимает буквально, как часть значения переменной.
Структура, лежащая в основе данных в Go
Следующий рисунок приведен из статьи про структуру данных в Go в блоге Russ Cox. Для хранения данных Go использует блоки памяти.
Рисунок 2.1 Структура, лежащая в основе данных в Go.
Если Вы хотите определить сразу несколько констант, переменных или импортировать несколько пакетов, Вы можете использовать групповое определение.
Если не указать, что значение константы равно iota , то значение первой константы в группе const() будет равно 0 . Если же константе, перед которой есть другая константа, явно не присвоено никакого значения, оно будет равно значению идущей перед ней константы. Если значение константы указано как iota , значения последующих после нее констант в группе, которым явно не присвоено никаких значений, также будут равны iota (И так до тех пор, пока не встретится константа с явно указанным значением, после этого значения всех идущих после нее констант с явно неуказанным значением будут равны ее значению - прим. переводчика на русский).
В Go есть ключевое слово iota , оно служит для того, чтобы обеспечить последовательное перечисление ( enum ), оно начинается с 0 и с каждым шагом увеличивается на 1 .
Причина краткости кода, написанного на Go - это то, что этому языку присущи некоторые моменты поведения по умолчанию:
- Все переменные, имя которых начинается с большой буквы, являются публичными; те, имя которых начинается с маленькой буквы - приватными.
- То же относится к функциям и константам, в Go нет ключевых слов public или private .
Массивы, срезы, карты
Массив в Go определяется так:
В [n]тип , n - длина массива, type - тип его элементов. Так же, как и в других языках, квадратные скобки [] используются для того, чтобы получить или присвоить значения элементам массива.
Поскольку длина массива является составной частью его типа, [3]int и [4]int - разные типы. Поэтому длину массива менять нельзя. Когда массивы используются в качестве аргументов, функции работают с их копиями, не ссылками! Если Вы хотите работать со ссылками, используйте срезы , о которых мы поговорим позже.
При определении массивов можно пользоваться коротким объявлением := .
Вам может захотеться использовать массивы в качестве элементов другого массива. Давайте посмотрим, как это делается:
Структура, лежащая в основе массива:
Рисунок 2.2 Отношения внутри многомерного массива
Часто тип 'массив' - не очень подходящий тип, например, когда при определении мы не знаем точно, какова будет длина массива. Поэтому нам нужен "динамический массив". В Go такой динамический массив называется срезом (slice) .
Вообще срез - это не динамический массив . Это ссылочный тип. срез указывает на лежащий в его основе массив , его объявление аналогично объявлению массива , но длина не указывается.
Так мы определяем срез и задаем его начальное значение:
Срез может переопределять существующие массивы и срезы. Срез использует array[i:j] , чтобы получить фрагмент массива array , где i - начальный индекс, а j - конечный, но имейте в виду, что array[j] не войдет в срез, так как длина среза равна j-i .
Имейте в виду разницу между срезом и массивом , когда определяете их. Для вычисления длины массива используется […] , но для определения среза - только [] .
Структура, лежащая в основе срезов:
Рисунок 2.3 Связь между срезом и массивом
Со срезами можно производить некоторые удобные операции:
- Первый элемент среза имеет индекс 0, ar[:n] равен ar[0:n] .
- Если второй индекс элемента не указан, он равен длине среза, ar[n:] равен ar[n:len(ar)] .
- Можно использовать ar[:] , чтобы срез был равен всему массиву, как следует из сказанного в двух предыдущих пунктах.
Еще примеры, относящиеся к срезам :
Срез - ссылочный тип, поэтому при его изменении изменятся также значения всех остальных переменных, указывающих на тот же срез или массив. Например, возвращаясь к aSlice и bSlice , о которых шла речь выше, если изменить значение одного из элементов aSlice , bSlice тоже будет изменен.
Срез похож на struct и состоит из 3 частей:
Указатель на то, где начинается срез .
Емкость - длина от начального до конечного индексов среза .
Структура, лежащая в основе это кода:
Рисунок 2.4 Информация о срезе на основе массива
Срез имеет несколько встроенных функций:
- len возвращает длину среза .
- cap возвращает максимальную длину среза
- append присоединяет к срезу один или несколько элементов и возвращает новый срез .
- copy копирует элементы из одного среза в другой и возвращает количество скопированных элементов.
Внимание: append изменяет массив, на который указывает срез и затрагивает все остальные срезы, указывающие на тот же массив. Также, если срезу не хватает длины массива ( (cap-len) == 0 ), append возвращает новый массив, на который теперь будет указывать этот срез. В этом случае значения других срезов, указывающих на старый массив, не изменятся.
Поведение карты (map) похоже на то, как ведет себя словарь в Python. Чтобы определить карту, используйте map[типКлюча]типЗначения .
Давайте посмотрим на пример кода. Команды изменения и получения значений для карты похожи на соответствующие для среза , однако индекс для среза может быть только типа 'int', в то время как карта может использовать для этих целей гораздо больше: например int , string или вообще все, что захотите. Также можно использовать == и != , чтобы сравнивать значения между собой.
Несколько замечаний при использовании карт:
- элементы в карте неупорядоченны. Каждый раз, когда Вы печатаете карту , Вы получите различные результаты. Получить значения по индексу невозможно - следует использовать ключи .
- У карты нет фиксированной длины. Это ссылочный тип, как и срез .
- len (длина) работает также и с картой . Она возвращает количество ключей в карте.
- Изменить значение в карте очень просто. Чтобы изменить значение ключа one на 11 , нужно использовать выражение numbers["one"]=11 .
Чтобы задать значения элементам карты, нужно использовать форму ключ:значение , также у карты есть встроенные методы для того, чтобы проверить, содержит ли она заданный ключ.
Для того, чтобы удалить элемент в карте , используйте delete .
Как я уже говорил выше, карта является ссылочным типом. Если две карты указывают на один и тот же объект, любое его изменение затронет обе карты:
make выделяет память для объектов встроенных типов, таких как карта , срез , и канал , в то время как new служит для выделения памяти под сами типы.
new(T) размещает в памяти нулевое значение типа T и возвращает его адрес в памяти, типом которого является *T . В терминах Go оно возвращает указатель на нулевое значение типа T .
new возвращает указатели.
У встроенной функции make(T, args) другое предназначение, нежели у new(T) . make используется для slice(срезов) , map(карт) и channel(каналов) и возвращает стартовое значение типа T . Это делается потому, что данные для этих трех типов должны быть изначально проинициализированы перед тем, как на них указывать. Например, срез(slice) содержит указатель, который указывает на лежащий в его основе array(массив) , его длину и емкость. Пока эти данные не проинициализированы, значение slice равно nil , поэтому для slice , map и channel , make инициализирует лежащие в их основе данные и присваивает некоторые подходящие значения.
make возвращает ненулевые значения.
Следующий рисунок показывает, как отличаются new и make .
Рисунок 2.5 Выделение памяти для данных, лежащих в основе в случае make и new
Нулевое значение - это не пустое значение. Это то значение, которое в большинстве случаев является значением по умолчанию для переменной соответствующего типа. Вот список нулевых значений для некоторых типов:
Go check if file exists
In the following example, we check if the given file exists.
We call the os.Stat function on the file. If the function returns the os.ErrNotExist error, the file does not exist.
13 Answers 13
To check if a file doesn't exist, equivalent to Python's if not os.path.exists(filename) :
To check if a file exists, equivalent to Python's if os.path.exists(filename) :
Edited: per recent comments
sometimes it return ENOTDIR instead of NOTEXIST , for example, if /etc/bashrc exist, the /etc/bashrc/foobar will return ENOTDIR
The second snippet is more subtly wrong; the condition should be !os.IsNotExist(err) . It's possible the file exists but os.Stat fails for other reasons (eg. permission, failing disk). Using err == nil as the condition incorrectly categorises such failures as "the file does not exist".
Answer by Caleb Spare posted in gonuts mailing list.
os.MkdirAll works whether or not the paths already exist. (Also you need to check the error from that call.)
Instead of using os.Create , you should use os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) . That way you'll get an error if the file already exists. Also this doesn't have a race condition with something else making the file, unlike your version which checks for existence beforehand.
Thank you for quoting this because I had a lot of trouble finding how to create a file only if the file does not exist ( os.O_EXCL ) because I can never remember what these flags mean. I thought os.O_CREATE already implied that the file must be created and not exist beforehand.
You should use the os.Stat() and os.IsNotExist() functions as in the following example:
edit1: fixed issue of returning true when under some circumstances.
edit2: switched to using errors.Is() from os.IsNotExist(), which many say is a best-practice and here
Answer recommended by Go Language
The first thing to consider is that it is rare that you would only want to check whether or not a file exists. In most situations, you're trying to do something with the file if it exists. In Go, any time you try to perform some operation on a file that doesn't exist, the result should be a specific error ( os.ErrNotExist ) and the best thing to do is check whether the return err value (e.g. when calling a function like os.OpenFile(. ) ) is os.ErrNotExist .
The recommended way to do this used to be:
However, since the addition of errors.Is in Go 1.13 (released in late 2019), the new recommendation is to use errors.Is :
It's usually best to avoid using os.Stat to check for the existence of a file before you attempt to do something with it, because it will always be possible for the file to be renamed, deleted, etc. in the window of time before you do something with it.
However, if you're OK with this caveat and you really, truly just want to check whether a file exists without then proceeding to do something useful with it (as a contrived example, let's say that you're writing a pointless CLI tool that tells you whether or not a file exists and then exits ¯\_(ツ)_/¯ ), then the recommended way to do it would be:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
if _ , err := os . Stat ( "/path/to/whatever" ); os . IsNotExist ( err ) |
// path/to/whatever does not exist |
> |
if _ , err := os . Stat ( "/path/to/whatever" ); ! os . IsNotExist ( err ) |
// path/to/whatever exists |
> |
shinriyo commented Sep 10, 2017
fmt.Printf("Error: %s", err)
cuixin commented Nov 17, 2017
Go file last modified time
In the following example, we get the last modification time of the given file.
We get the last modification time from the FileInfo structure using its ModTime function.
Go list files
The filepath.Walk walks the file tree, calling the specified function for each file or directory in the tree, including root. The function is recursively walking all subdirectories.
In the code example, we search for files with .txt extension.
The matching files are stored in the files slice.
This is the root directory where we start searching.
The first parameter of the filepath.Walk is the root directory. The second parameter is the walk function; the function called by filepath.Walk to visit each each file or directory.
Print the error if there is one, but continue searching elsewhere.
We append the file to the files slice if the file is not a directory and it has the .txt extension.
Finally, we go over the files slice and print all matching files to the console.
I want to check the existence of file ./conf/app.ini in my Go code, but I can't find a good way to do that.
I know there is a method of File in Java: public boolean exists() , which returns true if the file or directory exists.
But how can this be done in Go?
Also note that depending on how you're going to use this information you've got a race condition. All you can say is that a little while ago the file did/did-not exist; by the time you act on the test the opposite may be true. Usually it's much better to check while doing whatever operation you intend to do (e.g. don't check before opening an existing or creating a new file but do f, err := os.Open(name) or f, err := os.OpenFile(name,os.O_CREATE|os.O_EXCL, mode) and then check os.IsNotExist(err) ).
cn27001 commented Sep 14, 2016
LaurenceOfAustralia commented Jun 7, 2017
Go copy file
The next example copies a file.
In the code example, we read the contents of the source file with ioutil.ReadFile and write data to the desitination file with ioutil.WriteFile .
Go read file
The ioutil.ReadFile reads the file specified as a parameter and returns the contents. The function reads the whole file in one go; therefore, it should not be used for large files.
In the code example, we read the contents of a text file and print it to the console.
A more appropriate way for a large file is to read it line by line. This way the program does not take huge amounts of memory.
The example reads a text file line by line.
The os.Open function opens the specified file for reading. If successful, the functions on the returned file can be used for reading; the associated file descriptor has mode O_RDONLY .
The bufio.NewScanner function returns a new Scanner to read from.
With the Scan function we advance to the next token. We get the advancement with the Text function. In the default mode, the Scan function advances by lines.
kshitij10496 commented Dec 20, 2017
Читайте также: