Golang изменить строку в файле

Обновлено: 06.07.2024

Пакет strings в Go имеет несколько функций для работы со строковым типом данных. Эти функции позволяют легко модифицировать и управлять строками. Функции здесь можно рассматривать как действия, которые мы выполняем над элементами нашего кода. Встроенные функции – это те, которые определены в языке программирования Go и доступны для использования.

В этом мануале мы рассмотрим несколько различных функций, которые можно использовать для работы со строками в Go.

Изменение регистра строк

Функции strings.ToUpper и strings.ToLower возвращают строки, преобразовывая все их буквы в прописные или строчные. Поскольку строки являются неизменяемым типом данных, возвращаемая строка будет новой строкой. Любые символы в строке, которые не являются буквами, не будут изменены.

Чтобы преобразовать строку «Perfect Blog» в верхний регистр, нужно использовать функцию strings.ToUpper:

ss := "Perfect Blog"
fmt.Println(strings.ToUpper(ss))
PERFECT BLOG

Чтобы преобразовать эту строку в нижний регистр, нужно использовать:

fmt.Println(strings.ToLower(ss))
perfect blog

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

package main
import (
"fmt"
"strings"
)
func main() ss := "Perfect Blog"
fmt.Println(strings.ToUpper(ss))
fmt.Println(strings.ToLower(ss))
>

Функции strings.ToUpper и strings.ToLower упрощают оценку и сравнение строк, обеспечивая согласованность регистра. Например, если пользователь ввел свое имя в нижнем регистре, вы все равно сможете определить, находится ли его имя в базе данных.

Функции поиска

Пакет strings имеет ряд функций, которые помогают определить, содержит ли строка определенную последовательность символов.

Функция Действие
strings.HasPrefix Ищет строку с начала
strings.HasSuffix Ищет строку с конца
strings.Contains Поиск в любом месте строки
strings.Count Подсчитывает, сколько раз встречается эта строка

Strings.HasPrefix и strings.HasSuffix позволяют проверить, начинается/заканчивается ли строка определенным набором символов.

ss := "Perfect Blog"
fmt.Println(strings.HasPrefix(ss, "Perfect"))
fmt.Println(strings.HasSuffix(ss, "Blog"))
true
true

Можно было бы использовать функцию strings.Contains, чтобы проверить, содержит ли «Perfect Blog» последовательность Bl:

fmt.Println(strings.Contains(ss, "Bl"))
true

Наконец, так можно увидеть, сколько раз буква е появляется во фразе Perfect Blog:

fmt.Println(strings.Count(ss, "е"))
2

Примечание. Все строки в Go чувствительны к регистру. Это означает, что Perfect и perfect – не одно и то же.

Теперь попробуйте узнать, сколько раз во фразе Perfect Blog встречается прописная Е:

fmt.Println(strings.Count(ss, "Е"))
0

Поскольку символы Е и е – не одно и тоже, вы получите 0.

Строковые функции позволяют найти или сравнить строки в вашей программе.

Определение длины строки

Встроенная функция len() возвращает количество символов в строке. Эта функция полезна в тех случаях, когда вам нужно задать минимальную или максимальную длину пароля или обрезать строки большего размера, чтобы они находились в определенных пределах (для сокращений, например).

Чтобы продемонстрировать эту функцию, давайте попробуем узнать длину такого предложения:

import (
"fmt"
"strings"
)
func main() openSource := "8host contributes to open source."
fmt.Println(len(openSource))
>
33

Имейте в виду, что функция len() будет подсчитывать все символы внутри двойных кавычек, включая буквы, цифры, пробелы и другие символы.

Функции управления строками

Функции strings.Join, strings.Split и strings.ReplaceAll – это несколько дополнительных вариантов для управления строками в Go.

Функция strings.Join полезна для объединения срезов строк в новую единственную строку.

Чтобы создать разделенную запятыми строку из срезов, можно было бы использовать эту функцию таким образом:

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

Аналогично можно и разбивать строки. Для этого можно использовать функцию strings.Split и разделить строку по пробелам:

balloon := "Johnny has a balloon."
s := strings.Split(balloon, " ")
fmt.Println(s)
[Johnny has a balloon]

На выходе получается срез. Так как мы использовали strings.Println, трудно понять, что именно получилось в выводе, просто посмотрев на него. Чтобы увидеть, что это действительно срез, используйте функцию fmt.Printf с оператором %q, чтобы заключить новые строки в кавычки:

fmt.Printf("%q", s)
["Johnny" "has" "a" "balloon."]

Еще одна полезная функция в дополнение к strings.Split – это strings.Fields. Разница в том, что strings.Fields игнорирует все пробелы и выделяет только действительные поля в строке:

data := " username password email date"
fields := strings.Fields(data)
fmt.Printf("%q", fields)
["username" "password" "email" "date"]

Функция strings.ReplaceAll может взять исходную строку и вернуть обновленную строку с заменой.

Предположим, что Джонни потерял свой воздушный шар. Поскольку у него больше нет шара, мы можем заменить подстроку «has» из исходной строки на «had» в новой строке:

fmt.Println(strings.ReplaceAll(balloon, "has", "had"))

Johnny had a balloon.

Использование строковых функций strings.Join, strings.Split и strings.ReplaceAll предоставит вам больше возможностей для управления строками в Go.

Заключение

В этом мануале вы узнали о некоторых общих функциях пакета string, которые вы можете использовать для работы со строками в ваших программах Go.

Во время создания программы зачастую требуется заменить определенную подстроку внутри строки. В стандартной библиотеке Go есть функция Replace и тип Replacer для замены сразу нескольких строк.

Как заменить части строки в Golang?

1. Создайте файл replace.go со следующим содержимым:


Рекомендуем вам супер TELEGRAM канал по Golang где собраны все материалы для качественного изучения языка. Удивите всех своими знаниями на собеседовании! 😎

Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.

out = strings . Replace ( refStringTwo , "lamb" , "wolf" , 2 )

2. Запустите код через go run replace.go ;
3. Посмотрите на вывод в терминале:

замена части строки golang

4. Создайте файл replacer.go со следующим содержимым:

replacer : = strings . NewReplacer ( "lamb" , "wolf" , "Mary" , "Jack" )

5. Запустите код через go run replacer.go ;
6. Посмотрите на результат в терминале:

замена строки go

Замена текста в строке используя регулярные выражения

7. Создайте файл regexp.go со следующим содержимым:

out : = regex . ReplaceAllString ( refString , "replacement" )

8. Запустите код через go run regexp.go ;
9. Посмотрите на результат в терминале:

замена строк

Функция Replace из пакета strings часто используется для простой замены. Последний целочисленный аргумент определяет, сколько будет выполнено замен. В случае с -1 заменяются все строки. Во втором случае использования Replace производится только две замены. Использование функции Replace описано в шагах 1-3.

Помимо функции Replace , в структуре Replacer также есть метод WriteString . Данный метод запишет все замены, определенные в Replacer . Главное предназначение данного типа в возможности его повторного использования. Он может сразу заменить несколько строк, что безопасно для конкурентного использования. Это показано в шагах 4-6.

Более сложным методом замены подстроки или даже совпадающего паттерна является использование регулярного выражения. Тип указателя Regex метода ReplaceAllString может использоваться для этих целей. На этапах 7-9 показано использование пакета regexp .

Когда требуется более сложная логика замены, лучше всего использовать пакет regexp и регулярные выражения.


Администрирую данный сайт с целью распространения как можно большего объема обучающего материала для языка программирования Go. В IT с 2008 года, с тех пор изучаю и применяю интересующие меня технологии. Проявляю огромный интерес к машинному обучению и анализу данных.

В предыдущем посте мы разобрались, как работать с потоками байт, но иногда нам нужно работать с конкретным набором байт в памяти. Хотя слайсы байт вполне подходят для многих задач, есть немало случаев, когда лучше использовать пакет bytes. Также мы рассмотрим сегодня и пакет strings, так как его API практически идентичен bytes, только он работает со строками.

Этот пост является одним из серии статей по более углублённому разбору стандартной библиотеки. Несмотря на то, что стандартная документация предоставляет массу полезной информации, в контексте реальных задач может быть непросто разобраться, что и когда использовать. Эта серия статей направлена на то, чтобы показать использование пакетов стандартной библиотеки в контексте реальных приложений. Если у вас есть вопросы или комментарии, вы всегда можете написать мне в Твиттер — @benbjohnson.

Краткое отступление о строках и байтах

Роб Пайк написал отличный и глубокий пост о строках, байтах, рунах и символах, но для этого поста я бы хотел дать более простое определение с точки зрения разработчика.

Слайс байт представляет собой изменяемый последовательный набор байт. Слегка многословно, поэтому давайте попробуем понять, что это значит.

У нас есть слайс байт:

Он изменяемый, поэтому вы можете изменять в нём элементы:

Вы также можете менять его размер:

И он последовательный, так как байты в памяти идут один за другим:

Строки же представляют собой неизменяемый последовательный набор байт фиксированного размера. Это означает, что вы не можете изменять строки — только создавать новые. Это важно понимать в контексте производительности программы. В программах, где нужна очень высокая производительность, постоянное создание большого количества строк создаст ощутимую нагрузку на сборщик мусора.

С точки зрения разработчика, строки лучше использовать, когда вы работаете с данными в UTF-8 — они могут быть использованы как ключи к map, в отличие от слайсов байт, например, и большинство API используют строки для представления строковых данных. С другой стороны, слайсы байт гораздо лучше подходят, когда вам нужно работать с сырыми байтами, при обработке потоков данных, например. Они также удобней, если вы хотите избежать новых выделений памяти и хотите переиспользовать память.

Адаптируя строки и слайсы для потоков

Одна из самых важных особенностей пакетов bytes и strings заключается в том, что в них реализованы интерфейсы io.Reader и io.Writer для работы с байтами и строками в памяти.

In-memory ридеры

Две самык недоиспользуемые функции в стандартной библиотеке Go это bytes.NewReader и strings.NewReader:

Я регулярно вижу код, где слайсы байт и строки сначала пишутся в bytes.Buffer, а потом буфер используется как ридер:

Такой подход требует лишних аллокаций памяти и может быть медленным. Гораздо эффективней будет использовать strings.Reader:

Этот способ работает также когда у вас есть много строк или слайсов байт, которые можно объединить с помощью [io.MultiReader]():

In-memory writer

Пакет bytes также реализует интерфейс io.Writer для слайсов байт в памяти с помощью типа Buffer. Он реализует почти все интерфейсы пакета io, кроме io.Closer и io.Seeker. Также в нём есть вспомогательный метод WriteString() для записи строки в конец буфера.

Я активно использую Buffer в unit-тестах для захвата вывода логов сервисов. Вы можете передать буфер как аргумент в log.New() и проверить вывод позже:

Но в продакшн коде, я редко использую Buffer. Несмотря на имя, я не использую его для буферизированного чтения и записи, так как специально для этого в стандартной библиотеке есть пакет bufio.

Организация пакета

На первый взгляд, пакеты bytes и strings кажутся очень большими, но на самом деле они представляют собой просто набор простых вспомогательных функций. Мы можем сгруппировать их по нескольким категориям:

  • Функции сравнения
  • Функции проверки
  • Функции префиксов/суффиксов
  • Функции замены
  • Функции объединения и разделения

Когда мы поймём, как эти функции сгруппированы, казавшийся большим API будет выглядеть гораздо более комфортным.

Функции сравнения

Когда у вас есть два слайса байт или две строки, вам может понадобится получить ответ на два вопроса. Первый — равны ли эти два объекта? И второй — какой из объектов идёт раньше при сортировке?

Равенство

Функция Equal() отвечает на первый вопрос:

Эта функция есть только в пакете bytes, так как строки можно сравнивать с помощью оператора ==.

Хотя проверка на равенство может показаться простой задачей, есть популярная ошибка в использовании strings.ToUpper() для проверки на равенство без учёта регистра:

Этот подход неправильный, он использует 2 аллокации для новых строк. Гораздо более правильный подход это использование EqualFold():

Слово Fold тут означает Unicode case-folding. Оно охватывает правила для верхнего и нижнего регистра не только для A-Z, но и для других языков, и умеет конвертировать φ в ϕ.

Сравнение

Чтобы узнать порядок для сортировке двух слайсов байт или строк, у нас есть функция Compare():

Эта функция возвращает -1, если a меньше b, 1, если a больше b и 0, если a и b равны. Эта функция присутствует в пакете strings исключительно для симметрии с bytes. Russ Cox даже призывает к тому, что "никто не должен использовать strings.Compare". Проще использовать встроенные операторы < и >.

"никто не должен использовать strings.Compare", Russ Cox

Обычно вам нужно сравнивать слайсы байт или строк при сортировке данных. Интерфейс sort.Interface нуждается в функции сравнения для метода Less(). Чтобы перевести тернарную форму возвращаемого значения Compare() в логическое значение для Less(), достаточно просто проверить на равенство с -1:

Функции проверки

Пакеты bytes и strings предоставляют несколько способов проверить или найти значение в строке или в слайсе байт.

Подсчёт

Если вы валидируете входные данные, может быть необходимо проверить наличие (или отсутствие) определённых байт в них. Для этого можно использовать функцию Contains():

Например, вы можете проверить наличие определённых нехороших слов:

Если же вам нужно найти точное количество вхождений искомой подстроки, вы можете использовать Count():

Ещё одно применение Count() — подсчёт количества рун в строке. Если передать пустой слайс или пустую строку в качестве sep аргумента, Count() вернет количество рун + 1. Это отличается от вывода len(), которая возвращает количество байт. Это разница важна, если вы работаете с мультибайтовыми символами Unicode:

Первая строка может показаться странной, потому что по факту там 5 рун, но не забывайте, что Count() возвращает количество рун плюс единицу.

Индексирование

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

Тут есть несколько функций для разных случаев. Index() ищет мультибайтовые слайсы. IndexByte() находит единичный байт в слайсе. IndexRune() ищет Unicode code-point в UTF-8 строке. IndexAny() работает аналогично IndexRune(), но ищет сразу несколько code-point-ов одновременно. В заключение, IndexRune() позволяет использовать свою собственную функцию для поиска индекса.

Также есть аналогичный набор функций для поиска первой позиции с конца:

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

Префиксы, суффиксы и удаление

Префиксы в программировании вам встретятся довольно часто. Например, пути в HTTP адресах часто сгруппированы по функционалу с помощью префиксов. Или, другой пример — специальный символ в начале строки, вроде "@", используется для упоминания пользователя.

Функции HasPrefix() и HasSuffix() позволяют вам проверить такие случаи:

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

Этот код выглядит просто, но если str окажется пустой строкой, вы получите панику. Функция HasPrefix() содержит эту проверку:

Удаление

Термин "удаление"(trimming) в пакетах bytes и strings означает удаление байт или рун в начале и/или конце слайса или строки. Сама обобщённая для этого функция — Trim():

Она удаляет все руны из набора cutset с обеих сторон — с начала и конца строки. Также можно удалять только с начала, или только с конца, используя TrimLeft() и TrimRight() соответсвенно.

Но чаще всего используются более конкретные варианты удаления — удаление пробелов, для этого есть функция TrimSpace():

Вы можете подумать, что удаления с cutset-ом равным "\n\r" может быть достаточно, но TrimSpace() умеет удалять также символы пробелов, определённые в Unicode. Сюда входят не только пробелы, перевод строки или символ табуляции, но и такие нестандартные символы как "thin space" или "hair space".

TrimSpace(), на самом деле, всего лишь обёртка над TrimFunc(), которая определяет символы, которые будут использоваться для удаления:

Таким образом можно очень просто создать свою функцию, которая будет удалять, скажем, только пробелы в конце строки:

В заключение, если вы хотите удалить не символы, а конкретную подстроку слева или справа, то для этого есть функции TrimPrefix() и TrimSuffix():

Они идут рука об руку с функциями HasPrefix() и HasSuffix() для проверки на наличие префикса или суфикса соответственно. Например, я использую их для bash-подобного дополнения путей конфигурационных файлов в домашней директории:

Функции замены

Простая замена

Иногда необходимо заменить подстроку или часть слайса. Для большинства простых случаев всё что вам нужно, это функция Replace():

Она заменяет любое вхождение old в вашей строке на new. Если значение n равно -1, то будут заменены все вхождения. Эта функция очень хорошо подходит, если нужно заменить простое слово по шаблону. Например, вы можете позволить пользователю использовать шаблон "$NOW" и заменить его на текущее время:

Если вам необходимо заменять сразу несколько различных вхождений, используйте strings.Replacer. Он принимает на вход пары старое/новое значение:

Замена регистра

Вы можете полагать, что работа с регистрами это просто — нижний и верхний, всего-то делов — но Go работает с Unicode, а Unicode никогда не бывает прост. Есть три типа регистров: верхний, нижний и заглавный регистры.

Верхний и нижний довольно просты для большинства языков, и достаточно использовать функции ToUpper() и ToLower():

Но, в некоторых языках правила регистров отличаются от общепринятых. К примеру, в турецком языке, i в верхнем регистре выглядит как İ. Для таких специальных случаев, есть специальные версии этих функций:

Далее, у нас есть ещё заглавный регистр и функция ToTitle():

Наверное вы очень удивитесь, когда увидите что ToTitle() переведёт все ваши символы в верхний регистр:

Это потому, что в Unicode заглавный регистр является специальным видом регистра, а не написанием первой буквы в слове в верхнем регистре. В большинстве случаев, заглавный и верхний регистр это одно и тоже, но есть несколько code point-ов, в которых это не так. Например, code point lj (да, это один code point) в верхнем регистре выглядит как LJ, а в заглавном — Lj.

Функция, которая вам нужна в этом случае, это, скорее всего, Title():

Её вывод будет более похож на правду:

Маппинг рун

Есть ещё один способ замены данных в слайсах байт и строках — функция Map():

Эта функция позволяет указать свою функцию для проверки и замены каждой руны. Если честно, я понятия не имел об этой функции, пока не начал писать этот пост, поэтому никакой личной истории использования не могу тут поведать.

Функции объединения и разделения

Довольно часто приходится работать со строками, содержащими разделители, по которым строку нужно разбивать. Например, пути в UNIX объединены двоеточиями, а формат CSV это, по сути, просто данные, записанные через запятую.

Разбиение строк

Для простого разбиения слайсов или подстрок, у нас есть Split()-функции:

Эти функции разбивают строку или слайс байт согласно разделителю и возвращают их в виде нескольких слайсов или подстрок. After()-функции включают и сам разделитель в подстроках, а N()-функции ограничивают количество возвращаемых разделений:

Разбиение строк является очень частой операцией, но обычно это происходит в контексте работы с файлом в формате CSV или UNIX-путей. Для таких случаев я использую пакеты encoding/csv и path соответственно.

Разбиение по категориям

Иногда вам понадобится указывать разделители в виде набора рун, а не серии рун. Наилучшим примером тут будет разбиение слов по пробелам разной длины. Просто вызвав Split() с пробелом в качестве разделителя, вы получите на выходе пустые подстроки, если на входе есть несколько пробелов подряд. Вместо этого, используйте функцию Fields():

Она трактует последовательные пробелы, как один разделитель:

Функция Fields() это простой враппер вокруг другой функции — FieldsFunc(), которая позволяет указать произвольную функцию для проверки рун на разделитель:

Объединение строк

Другая операция, которая часто используется при работе с данными — это объединение слайсов и строк. Для этого есть функция Join():

Одна из ошибок, которую я встречал, заключается в том, что разработчики пытаются реализовать объединение строк вручную и пишут что-то вроде:

Проблема с этим кодом в том, что в нём происходит очень много аллокаций памяти. Так как строки неизменяемы, каждая итерация создаёт новую строку. Функция strings.Join() же использует слайс байт в качестве буфера и конвертирует в строку в самом конце. Это минимизирует количество аллокаций памяти.

Разные функции

Есть две функции, которые я не смог однозначно отнести к какой-либо категории, поэтому они тут внизу. Первая, функция Repeat() позволяет создать строку из повторяющихся элементов. Честно, единственный раз, когда я её использовал, это чтобы создать линию, разделяющую вывод в терминале:

Другая функция — Runes() возвращает слайс рун в строке или слайсе байт, интерпретированном как UTF-8. Никогда не использовал эту функцию, так как цикл for по строке делает ровно то же самое, без лишних аллокаций.

Слайсы байт и строки это фундаментальные примитивы в Go. Они являются представлением байт или рун в памяти. Пакеты bytes и strings предоставляют большое количество вспомогательных функций, а также адаптеры для io.Reader и io.Writer интерфейсов.

Довольно легко упустить из виду многие из этих полезных функций из-за большого размера API этих пакетов, но, я надеюсь, что этот пост помог вам познакомиться с этими пакетами и узнать о тех возможностях, которые они дают.


Чтение с диска и запись на диск, а также перемещение по файловой системе — это основной элемент в любом языке. Узнаем, как все это делать в Go с помощью пакета os, который позволяет взаимодействовать с функциональностью операционной системы.

Создание и открытие файлов

Создание файлов происходит с помощью os.Create , а открытие — с помощью os.Open . И там и там принимается путь к файлу и возвращается структура File , а в случае неуспеха — ошибка с nil .

Когда os.Create вызывается в существующем файле, он этот файл обрезает: данные файла стираются. В то же время вызов os.Open в несуществующем файле приводит к ошибке.

В слу ч ае успеха возвращенная структура File используется для записи и чтения данных в файле (дальше в статье будет приведен пример того, как файл открывается, читается фрагмент за фрагментом и закрывается).

После взаимодействия с возвращенным файлом закрываем его с помощью File.Close .

Чтение файлов

Один из способов обработки файла — прочитать сразу все содержащиеся в нем данные. Делается это с использованием os.ReadFile . Вводимые данные — это путь к файлу, а выходные данные — это байтовый массив данных файла и ошибка в случае неуспеха.

При обработке текстового файла для получения текста файла нужно преобразовать получаемый на выходе массив байтов в строку.

Имейте в виду, что os.ReadFile прочитает весь файл и загрузит его данные в память. И чем больше файл, тем больший объем памяти будет потребляться при использовании os.ReadFile .

Эффективный с точки зрения потребления памяти подход связан с пофрагментной обработкой файла, осуществляемой с помощью os.Open .

После открытия файла происходит многократный вызов File.Read до EOF (конца файла).

File.Read принимает байтовый массив b и загружает до len(b) байтов из файла в b . А затем возвращает количество прочитанных байтов bytesRead и ошибку, если что-то пойдет не так. При bytesRead равным 0 нажимаем EOF и заканчиваем обработку файла.

В приведенном выше коде из файла загружается максимум 10 байтов. Они обрабатываются, и этот процесс повторяется до EOF (конца файла).

В случае с более крупными файлами при этом подходе потребляется намного меньше памяти, чем при загрузке сразу всего файла.

Запись и добавление в файлы

Для записи байтов в файл существует аналогичная os.ReadFile функция os.WriteFile .

Что следует учесть при использовании os.WriteFile :

  • Обязательно преобразуйте данные для записи в []byte , прежде чем передавать их в os.WriteFile .
  • Биты полномочий необходимы для создания файла, если он еще не существует. Но на них заострять внимание не стоит.
  • Если путь к файлу уже существует, os.WriteFile переопределит исходные данные в файле с помощью новых записываемых данных.

os.WriteFile хорош для создания нового файла или его переопределения. Но он не работает, когда нужно сделать добавление к имеющемуся содержимому файла. Для добавления в файл нужно задействовать os.OpenFile .

Согласно документации, os.OpenFile — это более обобщенная версия os.Open и os.Create . И os.Create , и os.Open внутренне вызывают его.

Кроме пути к файлу, os.OpenFile принимает флаги int и perm (биты полномочий) и возвращает структуру File . Для выполнения таких операций, как чтение и запись, в os.OpenFile должна быть указана правильная комбинация флагов .

O_APPEND и O_WRONLY объединяют с побитовым ИЛИ и передают в os.OpenFile для получения структуры File . После этого при вызове File.Write с любыми передаваемыми данными эти данные будут добавлены в конец файла.

Удаление файлов

os.Remove принимает путь к файлу или пустому каталогу и удаляет этот файл/каталог. Если файл не существует, будет возвращена ошибка с nil .

Освоив основы работы с файлами, перейдем теперь к каталогам.

Создание каталогов

Для создания нового каталога используется os.Mkdir . Эта функция принимает имя каталога и биты полномочий, и так создается новый каталог. Если os.Mkdir не создаст каталог, будет возвращена ошибка с nil .

В некоторых ситуациях бывают нужны временные каталоги, которые существуют только во время выполнения программы. Для создания таких каталогов используется os.MkdirTemp .

os.MkdirTemp снабжает создаваемые временные каталоги уникальными именами, даже когда происходят вызовы от нескольких горутин или программ (источник). Закончив работу с временным каталогом, обязательно удалите вместе с его содержимым с помощью os.RemoveAll .

Чтение каталогов и перемещение по ним

Сначала с помощью os.Getwd получим текущий рабочий каталог:

В добавок к изменению рабочего каталога у нас есть возможность получить дочерний каталог. Делается это с помощью os.ReadDir . Эта функция принимает путь к каталогу и возвращает массив структур DirEntry и ошибку c nil в случае неуспеха.

Вот пример использования:

Пройдемся по каталогу

filepath.WalkDir принимает каталог root , из которого мы стартуем, и функцию обратного вызова fn следующего типа:

fn будет вызываться в каждом файле и подкаталоге каталога root . Вот пример подсчета всех файлов в корневом каталоге:

Читайте также: